OpenSTA/verilog/test/cpp/TestVerilog.cc

2819 lines
85 KiB
C++

#include <gtest/gtest.h>
#include <string>
#include "VerilogNamespace.hh"
#include "PortDirection.hh"
#include "VerilogReader.hh"
#include "verilog/VerilogReaderPvt.hh"
namespace sta {
class VerilogTest : public ::testing::Test {};
// Simple names should pass through
TEST_F(VerilogTest, SimpleCell) {
EXPECT_EQ(cellVerilogName("INV"), "INV");
}
TEST_F(VerilogTest, SimpleInstance) {
EXPECT_EQ(instanceVerilogName("u1"), "u1");
}
TEST_F(VerilogTest, SimpleNet) {
EXPECT_EQ(netVerilogName("wire1"), "wire1");
}
TEST_F(VerilogTest, SimplePort) {
EXPECT_EQ(portVerilogName("clk"), "clk");
}
// Bus names
TEST_F(VerilogTest, PortBusName) {
std::string result = portVerilogName("data[0]");
EXPECT_FALSE(result.empty());
}
TEST_F(VerilogTest, NetBusName) {
std::string result = netVerilogName("bus[3]");
EXPECT_FALSE(result.empty());
}
// Names with special characters need escaping
TEST_F(VerilogTest, EscapedCellName) {
std::string result = cellVerilogName("\\cell/name");
EXPECT_FALSE(result.empty());
}
TEST_F(VerilogTest, InstanceWithSlash) {
std::string result = instanceVerilogName("u1/u2");
EXPECT_FALSE(result.empty());
}
// Verilog to STA conversions
TEST_F(VerilogTest, ModuleToSta) {
std::string name = "top";
std::string result = moduleVerilogToSta(&name);
EXPECT_EQ(result, "top");
}
TEST_F(VerilogTest, InstanceToSta) {
std::string name = "inst1";
std::string result = instanceVerilogToSta(&name);
EXPECT_EQ(result, "inst1");
}
TEST_F(VerilogTest, EscapedToSta) {
std::string name = "\\esc_name ";
std::string result = instanceVerilogToSta(&name);
EXPECT_FALSE(result.empty());
}
TEST_F(VerilogTest, NetToSta) {
std::string name = "net1";
std::string result = netVerilogToSta(&name);
EXPECT_EQ(result, "net1");
}
TEST_F(VerilogTest, PortToSta) {
std::string name = "port_a";
std::string result = portVerilogToSta(&name);
EXPECT_EQ(result, "port_a");
}
////////////////////////////////////////////////////////////////
// VerilogNamespace - escaped name conversion tests
////////////////////////////////////////////////////////////////
// Names with special chars (non-alphanumeric, non-underscore) need escaping
TEST_F(VerilogTest, CellEscapedSpecialChar) {
// '/' is a special character, should cause escaping
std::string result = cellVerilogName("cell/name");
// Should be escaped: \cell/name (space at end)
EXPECT_EQ(result.front(), '\\');
EXPECT_EQ(result.back(), ' ');
}
TEST_F(VerilogTest, CellWithDot) {
std::string result = cellVerilogName("cell.name");
EXPECT_EQ(result.front(), '\\');
EXPECT_EQ(result.back(), ' ');
}
TEST_F(VerilogTest, CellPureAlphaNumUnderscore) {
// Names with only [a-zA-Z0-9_] should NOT be escaped
std::string result = cellVerilogName("my_cell_123");
EXPECT_EQ(result, "my_cell_123");
}
TEST_F(VerilogTest, InstanceEscaped) {
std::string result = instanceVerilogName("u1.u2");
EXPECT_EQ(result.front(), '\\');
}
TEST_F(VerilogTest, InstancePure) {
std::string result = instanceVerilogName("inst_1");
EXPECT_EQ(result, "inst_1");
}
TEST_F(VerilogTest, NetBusEscaped) {
// Net names with bus brackets should be handled
std::string result = netVerilogName("data[0]");
EXPECT_FALSE(result.empty());
// Should contain [0]
EXPECT_NE(result.find("[0]"), std::string::npos);
}
TEST_F(VerilogTest, NetNoBus) {
std::string result = netVerilogName("simple_net");
EXPECT_EQ(result, "simple_net");
}
TEST_F(VerilogTest, NetEscapedNoBus) {
// Net with special chars but no bus
std::string result = netVerilogName("net/special");
EXPECT_EQ(result.front(), '\\');
}
TEST_F(VerilogTest, PortEscaped) {
std::string result = portVerilogName("port.a");
EXPECT_EQ(result.front(), '\\');
}
TEST_F(VerilogTest, PortWithBrackets) {
// Brackets in port names cause escaping via staToVerilog2
std::string result = portVerilogName("data[3]");
EXPECT_FALSE(result.empty());
}
TEST_F(VerilogTest, PortPure) {
std::string result = portVerilogName("clk_out");
EXPECT_EQ(result, "clk_out");
}
// Test sta-to-verilog with escape characters in input
TEST_F(VerilogTest, CellDoubleEscape) {
// Double backslash in sta name means literal backslash in verilog
std::string result = cellVerilogName("cell\\\\name");
EXPECT_FALSE(result.empty());
}
TEST_F(VerilogTest, CellEscapePrefix) {
// Single backslash followed by non-backslash: escape is skipped
std::string result = cellVerilogName("\\special");
EXPECT_FALSE(result.empty());
}
// Verilog-to-STA conversions with escaped names
TEST_F(VerilogTest, EscapedModuleToSta) {
std::string name = "\\my/module ";
std::string result = moduleVerilogToSta(&name);
// Should strip leading \ and trailing space, but escape special chars
EXPECT_FALSE(result.empty());
EXPECT_NE(result.front(), '\\');
}
TEST_F(VerilogTest, EscapedNetToSta) {
std::string name = "\\net[0] ";
std::string result = netVerilogToSta(&name);
EXPECT_FALSE(result.empty());
}
TEST_F(VerilogTest, EscapedPortToSta) {
std::string name = "\\port/a ";
std::string result = portVerilogToSta(&name);
EXPECT_FALSE(result.empty());
}
TEST_F(VerilogTest, PlainModuleToSta) {
std::string name = "top_module";
std::string result = moduleVerilogToSta(&name);
EXPECT_EQ(result, "top_module");
}
TEST_F(VerilogTest, PlainNetToSta) {
std::string name = "wire1";
std::string result = netVerilogToSta(&name);
EXPECT_EQ(result, "wire1");
}
TEST_F(VerilogTest, PlainPortToSta) {
std::string name = "port_b";
std::string result = portVerilogToSta(&name);
EXPECT_EQ(result, "port_b");
}
// Escaped name with brackets (bus notation)
TEST_F(VerilogTest, EscapedInstanceWithBracket) {
std::string name = "\\inst[0] ";
std::string result = instanceVerilogToSta(&name);
EXPECT_FALSE(result.empty());
// Brackets should be escaped in STA name
EXPECT_NE(result.find("\\["), std::string::npos);
}
// Escaped name with divider
TEST_F(VerilogTest, EscapedInstanceWithDivider) {
std::string name = "\\u1/u2 ";
std::string result = instanceVerilogToSta(&name);
EXPECT_FALSE(result.empty());
// Divider should be escaped in STA name
EXPECT_NE(result.find("\\/"), std::string::npos);
}
// Escaped name with escape character
TEST_F(VerilogTest, EscapedNameWithEscapeChar) {
std::string name = "\\esc\\val ";
std::string result = instanceVerilogToSta(&name);
EXPECT_FALSE(result.empty());
}
// Escaped name without trailing space
TEST_F(VerilogTest, EscapedNoTrailingSpace) {
std::string name = "\\esc_name";
std::string result = instanceVerilogToSta(&name);
EXPECT_FALSE(result.empty());
}
////////////////////////////////////////////////////////////////
// Additional VerilogNamespace conversion tests for coverage
////////////////////////////////////////////////////////////////
// staToVerilog: names beginning with digit need escaping
TEST_F(VerilogTest, CellStartsWithDigit) {
std::string result = cellVerilogName("123abc");
EXPECT_EQ(result, "123abc"); // Only alphanumeric, no escape needed
}
// staToVerilog: name with space should be escaped
TEST_F(VerilogTest, CellWithSpace) {
std::string result = cellVerilogName("cell name");
EXPECT_EQ(result.front(), '\\');
EXPECT_EQ(result.back(), ' ');
}
// staToVerilog: single char name
TEST_F(VerilogTest, CellSingleChar) {
EXPECT_EQ(cellVerilogName("a"), "a");
}
// staToVerilog: empty name
TEST_F(VerilogTest, CellEmpty) {
EXPECT_EQ(cellVerilogName(""), "");
}
// netVerilogName bus indexing
TEST_F(VerilogTest, NetBusMultiDigit) {
std::string result = netVerilogName("data[15]");
EXPECT_NE(result.find("[15]"), std::string::npos);
}
TEST_F(VerilogTest, NetBusZero) {
std::string result = netVerilogName("wire[0]");
EXPECT_NE(result.find("[0]"), std::string::npos);
}
// portVerilogName with brackets (staToVerilog2 path)
TEST_F(VerilogTest, PortWithLeftBracket) {
std::string result = portVerilogName("port[5]");
EXPECT_EQ(result.front(), '\\');
EXPECT_EQ(result.back(), ' ');
}
// instanceVerilogName pure name
TEST_F(VerilogTest, InstanceAlphaNumUnderscore) {
EXPECT_EQ(instanceVerilogName("u_1_abc"), "u_1_abc");
}
// instanceVerilogName with various special chars
TEST_F(VerilogTest, InstanceWithColon) {
std::string result = instanceVerilogName("u1:u2");
EXPECT_EQ(result.front(), '\\');
EXPECT_EQ(result.back(), ' ');
}
TEST_F(VerilogTest, InstanceWithHash) {
std::string result = instanceVerilogName("u1#2");
EXPECT_EQ(result.front(), '\\');
}
TEST_F(VerilogTest, InstanceWithAt) {
std::string result = instanceVerilogName("u1@special");
EXPECT_EQ(result.front(), '\\');
}
// verilogToSta: escaped name with multiple special chars
TEST_F(VerilogTest, EscapedMultipleSpecial) {
std::string name = "\\u1/u2[3] ";
std::string result = instanceVerilogToSta(&name);
EXPECT_FALSE(result.empty());
// Both / and [ and ] should be escaped
EXPECT_NE(result.find("\\/"), std::string::npos);
EXPECT_NE(result.find("\\["), std::string::npos);
EXPECT_NE(result.find("\\]"), std::string::npos);
}
// verilogToSta: escaped name with backslash inside
TEST_F(VerilogTest, EscapedWithBackslash) {
std::string name = "\\a\\b ";
std::string result = instanceVerilogToSta(&name);
EXPECT_FALSE(result.empty());
// The backslash inside should be escaped as \\
EXPECT_NE(result.find("\\\\"), std::string::npos);
}
// netVerilogName with special chars and no bus
TEST_F(VerilogTest, NetSpecialNoBus) {
std::string result = netVerilogName("net.a");
EXPECT_EQ(result.front(), '\\');
EXPECT_EQ(result.back(), ' ');
}
// netVerilogName pure alphanumeric
TEST_F(VerilogTest, NetPureAlpha) {
EXPECT_EQ(netVerilogName("wire_abc_123"), "wire_abc_123");
}
// cellVerilogName with double backslash (literal backslash in name)
TEST_F(VerilogTest, CellDoubleBackslash) {
// Double backslash means literal backslash in sta name
std::string result = cellVerilogName("a\\\\b");
EXPECT_FALSE(result.empty());
}
// netVerilogToSta with plain name
TEST_F(VerilogTest, NetToStaPlain) {
std::string name = "simple_wire";
EXPECT_EQ(netVerilogToSta(&name), "simple_wire");
}
// portVerilogToSta with plain name
TEST_F(VerilogTest, PortToStaPlain) {
std::string name = "port_clk";
EXPECT_EQ(portVerilogToSta(&name), "port_clk");
}
// moduleVerilogToSta plain
TEST_F(VerilogTest, ModuleToStaPlain) {
std::string name = "mod_top";
EXPECT_EQ(moduleVerilogToSta(&name), "mod_top");
}
// verilogToSta: escaped name without trailing space
TEST_F(VerilogTest, EscapedNoSpace) {
std::string name = "\\name";
std::string result = instanceVerilogToSta(&name);
EXPECT_FALSE(result.empty());
// "ame" (without leading 'n' because 'n' is first char after \ which is stripped)
// Actually: ignoring leading '\', copy the rest. "name" has no trailing space.
EXPECT_EQ(result, "name");
}
// staToVerilog with single backslash followed by non-backslash
TEST_F(VerilogTest, CellSingleEscape) {
// Single backslash means escape next char in sta name
// e.g., "a\[b" has a literal [ in the sta name
std::string result = cellVerilogName("a\\[b");
EXPECT_FALSE(result.empty());
// The \[ should cause the name to be escaped
EXPECT_EQ(result.front(), '\\');
}
// portVerilogName with only underscore
TEST_F(VerilogTest, PortUnderscoreOnly) {
EXPECT_EQ(portVerilogName("_"), "_");
}
// cellVerilogName with only underscore
TEST_F(VerilogTest, CellUnderscoreOnly) {
EXPECT_EQ(cellVerilogName("_"), "_");
}
// netVerilogName with escaped bus
TEST_F(VerilogTest, NetEscapedBus) {
// sta_name "data\\[0\\]" means literal brackets in name
std::string result = netVerilogName("data\\[0\\]");
EXPECT_FALSE(result.empty());
}
////////////////////////////////////////////////////////////////
// R5_ tests for additional verilog coverage
////////////////////////////////////////////////////////////////
// staToVerilog: names with dollar sign
TEST_F(VerilogTest, CellWithDollar) {
std::string result = cellVerilogName("cell$gen");
EXPECT_EQ(result.front(), '\\');
EXPECT_EQ(result.back(), ' ');
}
// staToVerilog: name with tab character
TEST_F(VerilogTest, CellWithTab) {
std::string result = cellVerilogName("cell\tname");
EXPECT_EQ(result.front(), '\\');
}
// staToVerilog: instance with brackets
TEST_F(VerilogTest, InstanceWithBrackets) {
std::string result = instanceVerilogName("inst[0]");
EXPECT_EQ(result.front(), '\\');
EXPECT_EQ(result.back(), ' ');
}
// verilogToSta: empty escaped name
TEST_F(VerilogTest, EmptyEscapedName) {
std::string name = "\\";
std::string result = instanceVerilogToSta(&name);
EXPECT_TRUE(result.empty());
}
// verilogToSta: escaped name with only space
TEST_F(VerilogTest, EscapedOnlySpace) {
std::string name = "\\ ";
std::string result = instanceVerilogToSta(&name);
EXPECT_TRUE(result.empty());
}
// netVerilogName: escaped characters with bus notation
TEST_F(VerilogTest, NetEscapedWithBus) {
std::string result = netVerilogName("net.a[3]");
EXPECT_FALSE(result.empty());
}
// portVerilogName: special character with underscore
TEST_F(VerilogTest, PortSpecialWithUnderscore) {
std::string result = portVerilogName("_port.a_");
EXPECT_EQ(result.front(), '\\');
}
// cellVerilogName: name with only special chars
TEST_F(VerilogTest, CellOnlySpecialChars) {
std::string result = cellVerilogName("./#@");
EXPECT_EQ(result.front(), '\\');
EXPECT_EQ(result.back(), ' ');
}
// instanceVerilogToSta: plain unescaped name
TEST_F(VerilogTest, UnescapedInstance) {
std::string name = "plain_inst";
std::string result = instanceVerilogToSta(&name);
EXPECT_EQ(result, "plain_inst");
}
// netVerilogToSta: escaped name with bus notation
TEST_F(VerilogTest, EscapedNetBus) {
std::string name = "\\data[7:0] ";
std::string result = netVerilogToSta(&name);
EXPECT_FALSE(result.empty());
}
// moduleVerilogToSta: escaped module name
TEST_F(VerilogTest, EscapedModule) {
std::string name = "\\mod/special ";
std::string result = moduleVerilogToSta(&name);
EXPECT_FALSE(result.empty());
}
// portVerilogToSta: escaped port name
TEST_F(VerilogTest, EscapedPort) {
std::string name = "\\port$gen ";
std::string result = portVerilogToSta(&name);
EXPECT_FALSE(result.empty());
}
// netVerilogName: name with backslash-escaped bracket
TEST_F(VerilogTest, NetEscapedBracketSlash) {
std::string result = netVerilogName("a\\[b");
EXPECT_FALSE(result.empty());
}
// portVerilogName: name that is just digits
TEST_F(VerilogTest, PortJustDigits) {
std::string result = portVerilogName("12345");
// All digits - alphanumeric, no escaping needed
EXPECT_EQ(result, "12345");
}
// cellVerilogName: name with hyphen
TEST_F(VerilogTest, CellWithHyphen) {
std::string result = cellVerilogName("cell-name");
EXPECT_EQ(result.front(), '\\');
EXPECT_EQ(result.back(), ' ');
}
// instanceVerilogName: name with equal sign
TEST_F(VerilogTest, InstanceWithEquals) {
std::string result = instanceVerilogName("inst=val");
EXPECT_EQ(result.front(), '\\');
}
// netVerilogName: name with percent
TEST_F(VerilogTest, NetWithPercent) {
std::string result = netVerilogName("net%1");
EXPECT_EQ(result.front(), '\\');
EXPECT_EQ(result.back(), ' ');
}
// portVerilogName: name with plus
TEST_F(VerilogTest, PortWithPlus) {
std::string result = portVerilogName("port+a");
EXPECT_EQ(result.front(), '\\');
}
// instanceVerilogToSta: escaped name with various special chars
TEST_F(VerilogTest, EscapedInstanceComplex) {
std::string name = "\\inst.a/b[c] ";
std::string result = instanceVerilogToSta(&name);
EXPECT_FALSE(result.empty());
// The result should contain the original special characters in some form
EXPECT_GT(result.size(), 3u);
}
// netVerilogToSta: plain net with underscore
TEST_F(VerilogTest, PlainNetUnderscore) {
std::string name = "_net_wire_";
std::string result = netVerilogToSta(&name);
EXPECT_EQ(result, "_net_wire_");
}
// portVerilogToSta: plain port with numbers
TEST_F(VerilogTest, PlainPortNumeric) {
std::string name = "port_123";
std::string result = portVerilogToSta(&name);
EXPECT_EQ(result, "port_123");
}
// moduleVerilogToSta: plain module with mixed case
TEST_F(VerilogTest, PlainModuleMixedCase) {
std::string name = "MyModule_V2";
std::string result = moduleVerilogToSta(&name);
EXPECT_EQ(result, "MyModule_V2");
}
// cellVerilogName: name with tilde
TEST_F(VerilogTest, CellWithTilde) {
std::string result = cellVerilogName("cell~inv");
EXPECT_EQ(result.front(), '\\');
}
// instanceVerilogName: name with ampersand
TEST_F(VerilogTest, InstanceWithAmpersand) {
std::string result = instanceVerilogName("inst&and");
EXPECT_EQ(result.front(), '\\');
}
// netVerilogName: name with exclamation
TEST_F(VerilogTest, NetWithExclamation) {
std::string result = netVerilogName("net!rst");
EXPECT_EQ(result.front(), '\\');
}
// portVerilogName: name with pipe
TEST_F(VerilogTest, PortWithPipe) {
std::string result = portVerilogName("port|or");
EXPECT_EQ(result.front(), '\\');
}
// instanceVerilogToSta: escaped name without trailing space (edge case)
TEST_F(VerilogTest, EscapedNoTrailingSpaceComplex) {
std::string name = "\\inst/a[0]";
std::string result = instanceVerilogToSta(&name);
EXPECT_FALSE(result.empty());
}
// cellVerilogName: very long name
TEST_F(VerilogTest, CellLongName) {
std::string long_name(200, 'a');
std::string result = cellVerilogName(long_name.c_str());
EXPECT_EQ(result, long_name);
}
// cellVerilogName: very long name with special char
TEST_F(VerilogTest, CellLongEscapedName) {
std::string long_name(200, 'a');
long_name[100] = '/';
std::string result = cellVerilogName(long_name.c_str());
EXPECT_EQ(result.front(), '\\');
EXPECT_EQ(result.back(), ' ');
}
////////////////////////////////////////////////////////////////
// R6_ tests for additional verilog coverage
////////////////////////////////////////////////////////////////
// VerilogNetScalar: constructor and properties
TEST_F(VerilogTest, NetScalarConstruct) {
VerilogNetScalar net("wire1");
EXPECT_TRUE(net.isNamed());
EXPECT_TRUE(net.isScalar());
EXPECT_EQ(net.name(), "wire1");
EXPECT_FALSE(net.isNamedPortRef());
}
// VerilogNetScalar: with bus-like name
TEST_F(VerilogTest, NetScalarBusLikeName) {
VerilogNetScalar net("data");
EXPECT_TRUE(net.isScalar());
EXPECT_EQ(net.name(), "data");
}
// VerilogNetBitSelect: constructor and properties
TEST_F(VerilogTest, NetBitSelectConstruct) {
VerilogNetBitSelect net("data", 3);
EXPECT_TRUE(net.isNamed());
EXPECT_FALSE(net.isScalar());
// name() returns "data[3]" (includes index)
EXPECT_EQ(net.name(), "data[3]");
EXPECT_EQ(net.index(), 3);
}
// VerilogNetBitSelect: index 0
TEST_F(VerilogTest, NetBitSelectZero) {
VerilogNetBitSelect net("wire", 0);
EXPECT_EQ(net.index(), 0);
EXPECT_EQ(net.name(), "wire[0]");
}
// VerilogNetPartSelect: constructor and properties
TEST_F(VerilogTest, NetPartSelectConstruct) {
VerilogNetPartSelect net("bus", 7, 0);
EXPECT_TRUE(net.isNamed());
EXPECT_FALSE(net.isScalar());
EXPECT_EQ(net.name(), "bus");
EXPECT_EQ(net.fromIndex(), 7);
EXPECT_EQ(net.toIndex(), 0);
}
// VerilogNetPartSelect: ascending
TEST_F(VerilogTest, NetPartSelectAscending) {
VerilogNetPartSelect net("addr", 0, 15);
EXPECT_EQ(net.fromIndex(), 0);
EXPECT_EQ(net.toIndex(), 15);
}
// VerilogNetUnnamed: constructor and properties via VerilogNetConcat
TEST_F(VerilogTest, NetUnnamedConstruct) {
VerilogNetSeq *nets = new VerilogNetSeq;
VerilogNetConcat net(nets);
// VerilogNetConcat extends VerilogNetUnnamed
EXPECT_FALSE(net.isNamed());
EXPECT_TRUE(net.name().empty());
}
// VerilogNetNamed: constructor, destructor, name
TEST_F(VerilogTest, NetNamedConstruct) {
VerilogNetScalar net("test_named");
EXPECT_TRUE(net.isNamed());
EXPECT_EQ(net.name(), "test_named");
}
// VerilogNetNamed: destructor (via delete)
TEST_F(VerilogTest, NetNamedDelete) {
VerilogNetNamed *net = new VerilogNetScalar("to_delete");
EXPECT_EQ(net->name(), "to_delete");
delete net;
}
// VerilogNetPortRef: constructor
TEST_F(VerilogTest, NetPortRefConstruct) {
VerilogNetPortRefScalarNet ref("port_a");
EXPECT_TRUE(ref.isNamedPortRef());
EXPECT_EQ(ref.name(), "port_a");
EXPECT_FALSE(ref.hasNet());
}
// VerilogNetPortRefScalarNet: with net name
TEST_F(VerilogTest, NetPortRefScalarNetWithName) {
VerilogNetPortRefScalarNet ref("port_a", "wire_a");
EXPECT_TRUE(ref.isNamedPortRef());
EXPECT_TRUE(ref.isNamedPortRefScalarNet());
EXPECT_TRUE(ref.isScalar());
EXPECT_TRUE(ref.hasNet());
EXPECT_EQ(ref.netName(), "wire_a");
}
// VerilogNetPortRefScalarNet: set net name
TEST_F(VerilogTest, NetPortRefScalarNetSetName) {
VerilogNetPortRefScalarNet ref("port_a");
EXPECT_FALSE(ref.hasNet());
ref.setNetName("wire_b");
EXPECT_TRUE(ref.hasNet());
EXPECT_EQ(ref.netName(), "wire_b");
}
// VerilogNetPortRefScalar: constructor with net
TEST_F(VerilogTest, NetPortRefScalarConstruct) {
VerilogNetScalar *inner_net = new VerilogNetScalar("inner_wire");
VerilogNetPortRefScalar ref("port_b", inner_net);
EXPECT_TRUE(ref.isNamedPortRef());
EXPECT_TRUE(ref.isScalar());
EXPECT_TRUE(ref.hasNet());
// ref owns inner_net and will delete it
}
// VerilogNetPortRefScalar: constructor with null net
TEST_F(VerilogTest, NetPortRefScalarNullNet) {
VerilogNetPortRefScalar ref("port_c", nullptr);
EXPECT_TRUE(ref.isNamedPortRef());
EXPECT_FALSE(ref.hasNet());
}
// VerilogNetPortRefBit: constructor
TEST_F(VerilogTest, NetPortRefBitConstruct) {
VerilogNetScalar *inner_net = new VerilogNetScalar("inner2");
VerilogNetPortRefBit ref("port_d", 3, inner_net);
EXPECT_TRUE(ref.isNamedPortRef());
// name() returns bit_name_ which is "port_d[3]"
std::string rname = ref.name();
EXPECT_FALSE(rname.empty());
}
// VerilogNetPortRefPart: constructor and name
TEST_F(VerilogTest, NetPortRefPartConstruct) {
VerilogNetScalar *inner_net = new VerilogNetScalar("inner3");
VerilogNetPortRefPart ref("port_e", 7, 0, inner_net);
EXPECT_TRUE(ref.isNamedPortRef());
std::string rname = ref.name();
EXPECT_FALSE(rname.empty());
EXPECT_EQ(ref.toIndex(), 0);
}
// VerilogNetConcat: constructor with nets
TEST_F(VerilogTest, NetConcatConstruct) {
VerilogNetSeq *nets = new VerilogNetSeq;
nets->push_back(new VerilogNetScalar("a"));
nets->push_back(new VerilogNetScalar("b"));
VerilogNetConcat concat(nets);
EXPECT_FALSE(concat.isNamed());
}
// VerilogDclArg: constructor with name
TEST_F(VerilogTest, DclArgName) {
VerilogDclArg arg("wire_name");
EXPECT_EQ(arg.netName(), "wire_name");
EXPECT_TRUE(arg.isNamed());
EXPECT_EQ(arg.assign(), nullptr);
}
// VerilogDclArg: constructor with assign
TEST_F(VerilogTest, DclArgAssign) {
VerilogNetScalar *lhs = new VerilogNetScalar("out");
VerilogNetScalar *rhs = new VerilogNetScalar("in");
VerilogAssign *assign = new VerilogAssign(lhs, rhs, 1);
VerilogDclArg arg(assign);
EXPECT_FALSE(arg.isNamed());
EXPECT_NE(arg.assign(), nullptr);
}
// VerilogAssign: constructor and accessors
TEST_F(VerilogTest, AssignConstruct) {
VerilogNetScalar *lhs = new VerilogNetScalar("out");
VerilogNetScalar *rhs = new VerilogNetScalar("in");
VerilogAssign assign(lhs, rhs, 10);
EXPECT_TRUE(assign.isAssign());
EXPECT_EQ(assign.lhs(), lhs);
EXPECT_EQ(assign.rhs(), rhs);
EXPECT_EQ(assign.line(), 10);
}
// VerilogStmt: constructor and properties
TEST_F(VerilogTest, StmtConstruct) {
// VerilogStmt is abstract, test through VerilogAssign
VerilogNetScalar *lhs = new VerilogNetScalar("a");
VerilogNetScalar *rhs = new VerilogNetScalar("b");
VerilogAssign assign(lhs, rhs, 5);
EXPECT_FALSE(assign.isInstance());
EXPECT_FALSE(assign.isModuleInst());
EXPECT_FALSE(assign.isLibertyInst());
EXPECT_TRUE(assign.isAssign());
EXPECT_FALSE(assign.isDeclaration());
EXPECT_EQ(assign.line(), 5);
}
// VerilogStmt: destructor (via delete of derived)
TEST_F(VerilogTest, StmtDelete) {
VerilogNetScalar *lhs = new VerilogNetScalar("x");
VerilogNetScalar *rhs = new VerilogNetScalar("y");
VerilogStmt *stmt = new VerilogAssign(lhs, rhs, 1);
EXPECT_TRUE(stmt->isAssign());
delete stmt;
}
// VerilogInst: constructor and accessors
TEST_F(VerilogTest, InstConstruct) {
VerilogInst *inst = new VerilogModuleInst("INV", "u1", nullptr,
new VerilogAttrStmtSeq, 1);
EXPECT_TRUE(inst->isInstance());
EXPECT_TRUE(inst->isModuleInst());
EXPECT_EQ(inst->instanceName(), "u1");
EXPECT_EQ(inst->line(), 1);
delete inst;
}
// VerilogInst: setInstanceName
TEST_F(VerilogTest, InstSetName) {
VerilogModuleInst inst("BUF", "old_name", nullptr,
new VerilogAttrStmtSeq, 1);
EXPECT_EQ(inst.instanceName(), "old_name");
inst.setInstanceName("new_name");
EXPECT_EQ(inst.instanceName(), "new_name");
}
// VerilogModuleInst: hasPins with nullptr
TEST_F(VerilogTest, ModuleInstHasPinsNull) {
VerilogModuleInst inst("INV", "u1", nullptr,
new VerilogAttrStmtSeq, 1);
EXPECT_FALSE(inst.hasPins());
}
// VerilogModuleInst: hasPins with empty pins
TEST_F(VerilogTest, ModuleInstHasPinsEmpty) {
VerilogNetSeq *pins = new VerilogNetSeq;
VerilogModuleInst inst("INV", "u1", pins,
new VerilogAttrStmtSeq, 1);
EXPECT_FALSE(inst.hasPins());
}
// VerilogModuleInst: hasPins with pins
TEST_F(VerilogTest, ModuleInstHasPinsTrue) {
VerilogNetSeq *pins = new VerilogNetSeq;
pins->push_back(new VerilogNetScalar("wire1"));
VerilogModuleInst inst("INV", "u1", pins,
new VerilogAttrStmtSeq, 1);
EXPECT_TRUE(inst.hasPins());
}
// VerilogModuleInst: moduleName
TEST_F(VerilogTest, ModuleInstModuleName) {
VerilogModuleInst inst("BUF_X2", "buffer1", nullptr,
new VerilogAttrStmtSeq, 5);
EXPECT_EQ(inst.moduleName(), "BUF_X2");
}
// VerilogDcl: constructor with args seq
TEST_F(VerilogTest, DclConstructSeq) {
PortDirection::init();
VerilogDclArgSeq *args = new VerilogDclArgSeq;
args->push_back(new VerilogDclArg("wire1"));
args->push_back(new VerilogDclArg("wire2"));
VerilogDcl dcl(PortDirection::input(), args, new VerilogAttrStmtSeq, 1);
EXPECT_TRUE(dcl.isDeclaration());
EXPECT_FALSE(dcl.isBus());
EXPECT_EQ(dcl.size(), 1);
EXPECT_EQ(dcl.direction(), PortDirection::input());
}
// VerilogDcl: portName
TEST_F(VerilogTest, DclPortName) {
PortDirection::init();
VerilogDclArgSeq *args = new VerilogDclArgSeq;
args->push_back(new VerilogDclArg("my_wire"));
VerilogDcl dcl(PortDirection::output(), args, new VerilogAttrStmtSeq, 1);
std::string pname = dcl.portName();
EXPECT_EQ(pname, "my_wire");
}
// VerilogDcl: appendArg
TEST_F(VerilogTest, DclAppendArg) {
PortDirection::init();
VerilogDclArgSeq *args = new VerilogDclArgSeq;
args->push_back(new VerilogDclArg("w1"));
VerilogDcl dcl(PortDirection::input(), args, new VerilogAttrStmtSeq, 1);
dcl.appendArg(new VerilogDclArg("w2"));
EXPECT_EQ(dcl.args()->size(), 2u);
}
// VerilogDclBus: constructor with args seq
TEST_F(VerilogTest, DclBusConstructSeq) {
PortDirection::init();
VerilogDclArgSeq *args = new VerilogDclArgSeq;
args->push_back(new VerilogDclArg("bus_wire"));
VerilogDclBus dcl(PortDirection::input(), 7, 0, args,
new VerilogAttrStmtSeq, 1);
EXPECT_TRUE(dcl.isBus());
EXPECT_TRUE(dcl.isDeclaration());
EXPECT_EQ(dcl.fromIndex(), 7);
EXPECT_EQ(dcl.toIndex(), 0);
EXPECT_EQ(dcl.size(), 8);
}
// VerilogDclBus: constructor with single arg
TEST_F(VerilogTest, DclBusConstructSingle) {
PortDirection::init();
VerilogDclArg *arg = new VerilogDclArg("single_bus");
VerilogDclBus dcl(PortDirection::output(), 3, 0, arg,
new VerilogAttrStmtSeq, 1);
EXPECT_TRUE(dcl.isBus());
EXPECT_EQ(dcl.size(), 4);
}
// VerilogDclBus: ascending range
TEST_F(VerilogTest, DclBusAscending) {
PortDirection::init();
VerilogDclArgSeq *args = new VerilogDclArgSeq;
args->push_back(new VerilogDclArg("asc_bus"));
VerilogDclBus dcl(PortDirection::input(), 0, 7, args,
new VerilogAttrStmtSeq, 1);
EXPECT_EQ(dcl.fromIndex(), 0);
EXPECT_EQ(dcl.toIndex(), 7);
EXPECT_EQ(dcl.size(), 8);
}
// VerilogAttrStmt: constructor
TEST_F(VerilogTest, AttrStmtConstruct) {
VerilogAttrEntrySeq *entries = new VerilogAttrEntrySeq;
entries->push_back(new VerilogAttrEntry("key1", "val1"));
VerilogAttrStmt stmt(entries);
VerilogAttrEntrySeq *attrs = stmt.attrs();
EXPECT_NE(attrs, nullptr);
EXPECT_EQ(attrs->size(), 1u);
}
// VerilogAttrEntry: constructor and accessors
TEST_F(VerilogTest, AttrEntryConstruct) {
VerilogAttrEntry entry("my_attr", "my_value");
EXPECT_EQ(entry.key(), "my_attr");
EXPECT_EQ(entry.value(), "my_value");
}
// VerilogNetScalar: multiple instances
TEST_F(VerilogTest, MultipleNetScalars) {
VerilogNetScalar net1("a");
VerilogNetScalar net2("b");
VerilogNetScalar net3("c");
EXPECT_EQ(net1.name(), "a");
EXPECT_EQ(net2.name(), "b");
EXPECT_EQ(net3.name(), "c");
EXPECT_TRUE(net1.isScalar());
EXPECT_TRUE(net2.isScalar());
EXPECT_TRUE(net3.isScalar());
}
// VerilogNetPortRefScalarNet: empty net name
TEST_F(VerilogTest, PortRefScalarNetEmpty) {
VerilogNetPortRefScalarNet ref("port_a");
EXPECT_FALSE(ref.hasNet());
EXPECT_EQ(ref.netName(), "");
}
// VerilogNetPortRefBit: index 0
TEST_F(VerilogTest, PortRefBitIndex0) {
VerilogNetScalar *inner = new VerilogNetScalar("w");
VerilogNetPortRefBit ref("port", 0, inner);
std::string rname = ref.name();
EXPECT_FALSE(rname.empty());
}
// VerilogNetPortRefPart: ascending range
TEST_F(VerilogTest, PortRefPartAsc) {
VerilogNetScalar *inner = new VerilogNetScalar("w");
VerilogNetPortRefPart ref("port", 0, 3, inner);
std::string rname = ref.name();
EXPECT_FALSE(rname.empty());
EXPECT_EQ(ref.toIndex(), 3);
}
// VerilogDcl: single arg constructor
TEST_F(VerilogTest, DclSingleArg) {
PortDirection::init();
VerilogDclArg *arg = new VerilogDclArg("single_wire");
VerilogDcl dcl(PortDirection::input(), arg, new VerilogAttrStmtSeq, 1);
EXPECT_TRUE(dcl.isDeclaration());
EXPECT_EQ(dcl.args()->size(), 1u);
}
// Additional name conversion tests
TEST_F(VerilogTest, CellWithQuestionMark) {
std::string result = cellVerilogName("cell?name");
EXPECT_EQ(result.front(), '\\');
}
TEST_F(VerilogTest, InstanceWithSemicolon) {
std::string result = instanceVerilogName("inst;name");
EXPECT_EQ(result.front(), '\\');
}
TEST_F(VerilogTest, NetWithComma) {
std::string result = netVerilogName("net,name");
EXPECT_EQ(result.front(), '\\');
}
TEST_F(VerilogTest, PortWithParens) {
std::string result = portVerilogName("port(a)");
EXPECT_EQ(result.front(), '\\');
}
TEST_F(VerilogTest, CellWithCurlyBraces) {
std::string result = cellVerilogName("cell{name}");
EXPECT_EQ(result.front(), '\\');
}
TEST_F(VerilogTest, InstanceWithLessThan) {
std::string result = instanceVerilogName("inst<0>");
EXPECT_EQ(result.front(), '\\');
}
// VerilogToSta: net with bus range
TEST_F(VerilogTest, EscapedNetRange) {
std::string name = "\\data[7:0] ";
std::string result = netVerilogToSta(&name);
EXPECT_FALSE(result.empty());
}
// VerilogToSta: module with digit prefix
TEST_F(VerilogTest, ModuleDigitPrefix) {
std::string name = "123module";
std::string result = moduleVerilogToSta(&name);
EXPECT_EQ(result, "123module");
}
// portVerilogToSta: escaped
TEST_F(VerilogTest, EscapedPortComplex) {
std::string name = "\\port.a[0]/b ";
std::string result = portVerilogToSta(&name);
EXPECT_FALSE(result.empty());
}
// cellVerilogName round-trip with special chars
TEST_F(VerilogTest, RoundTripSpecialCell) {
// STA name with escaped bracket
std::string sta_name = "cell\\[0\\]";
std::string verilog = cellVerilogName(sta_name.c_str());
EXPECT_FALSE(verilog.empty());
}
// instanceVerilogName: name with backslash in middle
TEST_F(VerilogTest, InstanceBackslashMiddle) {
std::string result = instanceVerilogName("inst\\mid");
EXPECT_FALSE(result.empty());
}
// netVerilogName: escaped bracket bus
TEST_F(VerilogTest, NetEscapedBracketBus2) {
std::string result = netVerilogName("data\\[3\\]");
EXPECT_FALSE(result.empty());
}
////////////////////////////////////////////////////////////////
// R8_ tests for additional verilog coverage
////////////////////////////////////////////////////////////////
// VerilogNetScalar::isScalar - uncovered
TEST_F(VerilogTest, NetScalarIsScalar) {
VerilogNetScalar net("scalar_w");
EXPECT_TRUE(net.isScalar());
EXPECT_TRUE(net.isNamed());
EXPECT_EQ(net.name(), "scalar_w");
}
// VerilogNetBitSelect::isScalar - uncovered (returns false)
TEST_F(VerilogTest, NetBitSelectNotScalar) {
VerilogNetBitSelect net("bus_w", 5);
EXPECT_FALSE(net.isScalar());
EXPECT_TRUE(net.isNamed());
EXPECT_EQ(net.index(), 5);
EXPECT_EQ(net.name(), "bus_w[5]");
}
// VerilogNetPartSelect::isScalar - uncovered (returns false)
TEST_F(VerilogTest, NetPartSelectNotScalar) {
VerilogNetPartSelect net("range_w", 15, 0);
EXPECT_FALSE(net.isScalar());
EXPECT_EQ(net.fromIndex(), 15);
EXPECT_EQ(net.toIndex(), 0);
}
// VerilogNetPortRefScalarNet::isScalar - uncovered (returns true)
TEST_F(VerilogTest, NetPortRefScalarNetIsScalar) {
VerilogNetPortRefScalarNet ref("port_ref", "net_ref");
EXPECT_TRUE(ref.isScalar());
EXPECT_TRUE(ref.isNamedPortRef());
EXPECT_TRUE(ref.isNamedPortRefScalarNet());
EXPECT_TRUE(ref.hasNet());
}
// VerilogNetPortRefScalar::isScalar - uncovered (returns true)
TEST_F(VerilogTest, NetPortRefScalarIsScalar) {
VerilogNetScalar *inner = new VerilogNetScalar("inner_w");
VerilogNetPortRefScalar ref("pref_s", inner);
EXPECT_TRUE(ref.isScalar());
EXPECT_TRUE(ref.isNamedPortRef());
EXPECT_TRUE(ref.hasNet());
}
// VerilogNetUnnamed::isNamed - uncovered
TEST_F(VerilogTest, NetUnnamedIsNamed) {
VerilogNetSeq *nets = new VerilogNetSeq;
VerilogNetConcat concat(nets);
EXPECT_FALSE(concat.isNamed());
EXPECT_TRUE(concat.name().empty());
}
// VerilogNetUnnamed::name - returns empty string
TEST_F(VerilogTest, NetUnnamedName) {
VerilogNetSeq *nets = new VerilogNetSeq;
nets->push_back(new VerilogNetScalar("x"));
VerilogNetConcat concat(nets);
const std::string &n = concat.name();
EXPECT_TRUE(n.empty());
}
// VerilogNetPortRefBit::name - uncovered
TEST_F(VerilogTest, NetPortRefBitName) {
VerilogNetScalar *inner = new VerilogNetScalar("w1");
VerilogNetPortRefBit ref("port_bit", 7, inner);
std::string n = ref.name();
// name() should return something like "port_bit[7]"
EXPECT_FALSE(n.empty());
EXPECT_NE(n.find("7"), std::string::npos);
}
// VerilogNetPortRefBit: index 0
TEST_F(VerilogTest, NetPortRefBitIndex0) {
VerilogNetScalar *inner = new VerilogNetScalar("w2");
VerilogNetPortRefBit ref("p0", 0, inner);
std::string n = ref.name();
EXPECT_NE(n.find("0"), std::string::npos);
}
// VerilogNetPortRefBit: null inner net
TEST_F(VerilogTest, NetPortRefBitNullNet) {
VerilogNetPortRefBit ref("p_null", 3, nullptr);
EXPECT_FALSE(ref.hasNet());
std::string n = ref.name();
EXPECT_FALSE(n.empty());
}
// VerilogStmt::isAssign - uncovered on base
TEST_F(VerilogTest, StmtIsAssign) {
VerilogNetScalar *lhs = new VerilogNetScalar("a");
VerilogNetScalar *rhs = new VerilogNetScalar("b");
VerilogAssign assign(lhs, rhs, 1);
EXPECT_TRUE(assign.isAssign());
EXPECT_FALSE(assign.isInstance());
EXPECT_FALSE(assign.isModuleInst());
EXPECT_FALSE(assign.isLibertyInst());
EXPECT_FALSE(assign.isDeclaration());
}
// VerilogStmt destructor via delete
TEST_F(VerilogTest, StmtDestructor) {
VerilogNetScalar *lhs = new VerilogNetScalar("x");
VerilogNetScalar *rhs = new VerilogNetScalar("y");
VerilogStmt *stmt = new VerilogAssign(lhs, rhs, 42);
EXPECT_EQ(stmt->line(), 42);
delete stmt;
}
// VerilogInst: constructor and destructor
TEST_F(VerilogTest, InstConstructDestruct) {
VerilogModuleInst *inst = new VerilogModuleInst(
"AND2", "and_inst", nullptr, new VerilogAttrStmtSeq, 10);
EXPECT_TRUE(inst->isInstance());
EXPECT_TRUE(inst->isModuleInst());
EXPECT_FALSE(inst->isLibertyInst());
EXPECT_EQ(inst->instanceName(), "and_inst");
EXPECT_EQ(inst->moduleName(), "AND2");
EXPECT_EQ(inst->line(), 10);
delete inst;
}
// VerilogModuleInst: pins with content
TEST_F(VerilogTest, ModuleInstPinsContent) {
VerilogNetSeq *pins = new VerilogNetSeq;
pins->push_back(new VerilogNetScalar("a_wire"));
pins->push_back(new VerilogNetScalar("b_wire"));
VerilogModuleInst inst("OR2", "or_inst", pins,
new VerilogAttrStmtSeq, 20);
EXPECT_TRUE(inst.hasPins());
EXPECT_EQ(inst.moduleName(), "OR2");
}
// VerilogModuleInst: setInstanceName
TEST_F(VerilogTest, ModuleInstSetName) {
VerilogModuleInst inst("BUF", "old", nullptr,
new VerilogAttrStmtSeq, 1);
EXPECT_EQ(inst.instanceName(), "old");
inst.setInstanceName("new_name");
EXPECT_EQ(inst.instanceName(), "new_name");
}
// VerilogDcl: constructor with single arg
TEST_F(VerilogTest, DclSingleArg2) {
PortDirection::init();
VerilogDclArg *arg = new VerilogDclArg("single_wire");
VerilogDcl dcl(PortDirection::input(), arg, new VerilogAttrStmtSeq, 5);
EXPECT_TRUE(dcl.isDeclaration());
EXPECT_FALSE(dcl.isBus());
EXPECT_EQ(dcl.direction(), PortDirection::input());
EXPECT_EQ(dcl.portName(), "single_wire");
}
// VerilogDcl: output direction
TEST_F(VerilogTest, DclOutputDirection) {
PortDirection::init();
VerilogDclArgSeq *args = new VerilogDclArgSeq;
args->push_back(new VerilogDclArg("out_wire"));
VerilogDcl dcl(PortDirection::output(), args, new VerilogAttrStmtSeq, 1);
EXPECT_EQ(dcl.direction(), PortDirection::output());
}
// VerilogDcl: size
TEST_F(VerilogTest, DclSize) {
PortDirection::init();
VerilogDclArgSeq *args = new VerilogDclArgSeq;
args->push_back(new VerilogDclArg("w1"));
VerilogDcl dcl(PortDirection::input(), args, new VerilogAttrStmtSeq, 1);
EXPECT_EQ(dcl.size(), 1);
}
// VerilogDclBus: size calculation
TEST_F(VerilogTest, DclBusSize) {
PortDirection::init();
VerilogDclArgSeq *args = new VerilogDclArgSeq;
args->push_back(new VerilogDclArg("bus_w"));
VerilogDclBus dcl(PortDirection::input(), 31, 0, args,
new VerilogAttrStmtSeq, 1);
EXPECT_TRUE(dcl.isBus());
EXPECT_EQ(dcl.size(), 32);
}
// VerilogDclBus: ascending index
TEST_F(VerilogTest, DclBusAscending2) {
PortDirection::init();
VerilogDclArgSeq *args = new VerilogDclArgSeq;
args->push_back(new VerilogDclArg("bus_asc"));
VerilogDclBus dcl(PortDirection::input(), 0, 7, args,
new VerilogAttrStmtSeq, 1);
EXPECT_EQ(dcl.fromIndex(), 0);
EXPECT_EQ(dcl.toIndex(), 7);
EXPECT_EQ(dcl.size(), 8);
}
// VerilogDclBus: single-arg constructor
TEST_F(VerilogTest, DclBusSingleArg) {
PortDirection::init();
VerilogDclArg *arg = new VerilogDclArg("single_bus");
VerilogDclBus dcl(PortDirection::output(), 3, 0, arg,
new VerilogAttrStmtSeq, 1);
EXPECT_TRUE(dcl.isBus());
EXPECT_EQ(dcl.size(), 4);
}
// VerilogDclArg: named vs assign
TEST_F(VerilogTest, DclArgNamed) {
VerilogDclArg arg("my_net");
EXPECT_TRUE(arg.isNamed());
EXPECT_EQ(arg.netName(), "my_net");
EXPECT_EQ(arg.assign(), nullptr);
}
TEST_F(VerilogTest, DclArgAssign2) {
VerilogNetScalar *lhs = new VerilogNetScalar("out");
VerilogNetScalar *rhs = new VerilogNetScalar("in");
VerilogAssign *assign = new VerilogAssign(lhs, rhs, 1);
VerilogDclArg arg(assign);
EXPECT_FALSE(arg.isNamed());
EXPECT_NE(arg.assign(), nullptr);
}
// VerilogAssign: accessors
TEST_F(VerilogTest, AssignAccessors) {
VerilogNetScalar *lhs = new VerilogNetScalar("out");
VerilogNetScalar *rhs = new VerilogNetScalar("in");
VerilogAssign assign(lhs, rhs, 15);
EXPECT_TRUE(assign.isAssign());
EXPECT_EQ(assign.lhs(), lhs);
EXPECT_EQ(assign.rhs(), rhs);
EXPECT_EQ(assign.line(), 15);
}
// VerilogNetNamed: constructor and destructor
TEST_F(VerilogTest, NetNamedConstructDelete) {
VerilogNetNamed *net = new VerilogNetScalar("named_w");
EXPECT_TRUE(net->isNamed());
EXPECT_EQ(net->name(), "named_w");
delete net;
}
// VerilogNetConcat: with multiple nets
TEST_F(VerilogTest, NetConcatMultiple) {
VerilogNetSeq *nets = new VerilogNetSeq;
nets->push_back(new VerilogNetScalar("a"));
nets->push_back(new VerilogNetScalar("b"));
nets->push_back(new VerilogNetScalar("c"));
VerilogNetConcat concat(nets);
EXPECT_FALSE(concat.isNamed());
}
// VerilogNetPortRef: constructor
TEST_F(VerilogTest, NetPortRefConstruct2) {
VerilogNetPortRefScalarNet ref("port_x");
EXPECT_TRUE(ref.isNamedPortRef());
EXPECT_FALSE(ref.hasNet());
EXPECT_EQ(ref.name(), "port_x");
}
// VerilogNetPortRefScalarNet: various operations
TEST_F(VerilogTest, NetPortRefScalarNetOps) {
VerilogNetPortRefScalarNet ref("port_y", "net_y");
EXPECT_TRUE(ref.hasNet());
EXPECT_EQ(ref.netName(), "net_y");
ref.setNetName("new_net");
EXPECT_EQ(ref.netName(), "new_net");
}
// VerilogNetPortRefScalar: null net
TEST_F(VerilogTest, NetPortRefScalarNull) {
VerilogNetPortRefScalar ref("port_z", nullptr);
EXPECT_FALSE(ref.hasNet());
EXPECT_TRUE(ref.isScalar());
}
// VerilogNetPortRefPart: constructor
TEST_F(VerilogTest, NetPortRefPartConstruct2) {
VerilogNetScalar *inner = new VerilogNetScalar("w_part");
VerilogNetPortRefPart ref("port_part", 15, 0, inner);
EXPECT_TRUE(ref.isNamedPortRef());
EXPECT_EQ(ref.toIndex(), 0);
std::string n = ref.name();
EXPECT_FALSE(n.empty());
}
// VerilogNetPortRefPart: ascending range
TEST_F(VerilogTest, NetPortRefPartAscending) {
VerilogNetScalar *inner = new VerilogNetScalar("w_part_asc");
VerilogNetPortRefPart ref("port_asc", 0, 7, inner);
EXPECT_EQ(ref.toIndex(), 7);
}
// VerilogAttrStmt: construction
TEST_F(VerilogTest, AttrStmtConstruct2) {
VerilogAttrEntrySeq *entries = new VerilogAttrEntrySeq;
entries->push_back(new VerilogAttrEntry("key1", "val1"));
VerilogAttrStmt stmt(entries);
VerilogAttrEntrySeq *attrs = stmt.attrs();
EXPECT_NE(attrs, nullptr);
EXPECT_EQ(attrs->size(), 1u);
}
// VerilogAttrEntry: key and value
TEST_F(VerilogTest, AttrEntryKeyValue) {
VerilogAttrEntry entry("attr_key", "attr_value");
EXPECT_EQ(entry.key(), "attr_key");
EXPECT_EQ(entry.value(), "attr_value");
}
// VerilogNetBitSelect: various indices
TEST_F(VerilogTest, NetBitSelectLargeIndex) {
VerilogNetBitSelect net("data", 31);
EXPECT_EQ(net.index(), 31);
EXPECT_EQ(net.name(), "data[31]");
EXPECT_FALSE(net.isScalar());
}
// VerilogNetPartSelect: equal indices
TEST_F(VerilogTest, NetPartSelectEqual) {
VerilogNetPartSelect net("single", 5, 5);
EXPECT_EQ(net.fromIndex(), 5);
EXPECT_EQ(net.toIndex(), 5);
EXPECT_FALSE(net.isScalar());
}
// VerilogNetScalar: empty name
TEST_F(VerilogTest, NetScalarEmptyName) {
VerilogNetScalar net("");
EXPECT_TRUE(net.isScalar());
EXPECT_TRUE(net.name().empty());
}
// Additional name conversion edge cases
TEST_F(VerilogTest, CellNameWithBackslashEscape) {
std::string result = cellVerilogName("cell\\name");
EXPECT_FALSE(result.empty());
}
TEST_F(VerilogTest, InstanceNameAllDigits) {
std::string result = instanceVerilogName("0123456789");
EXPECT_EQ(result, "0123456789");
}
TEST_F(VerilogTest, NetNameSingleUnderscore) {
EXPECT_EQ(netVerilogName("_"), "_");
}
TEST_F(VerilogTest, PortNameSingleChar) {
EXPECT_EQ(portVerilogName("a"), "a");
}
TEST_F(VerilogTest, CellNameWithBraces) {
std::string result = cellVerilogName("{a,b}");
EXPECT_EQ(result.front(), '\\');
}
TEST_F(VerilogTest, InstanceNameWithStar) {
std::string result = instanceVerilogName("inst*2");
EXPECT_EQ(result.front(), '\\');
}
TEST_F(VerilogTest, NetNameWithQuote) {
std::string result = netVerilogName("net\"q");
EXPECT_EQ(result.front(), '\\');
}
TEST_F(VerilogTest, PortNameWithBacktick) {
std::string result = portVerilogName("port`tick");
EXPECT_EQ(result.front(), '\\');
}
// Verilog to STA conversions: edge cases
TEST_F(VerilogTest, EscapedInstanceOnlyBrackets) {
std::string name = "\\[0] ";
std::string result = instanceVerilogToSta(&name);
EXPECT_FALSE(result.empty());
}
TEST_F(VerilogTest, EscapedNetOnlySlash) {
std::string name = "\\/ ";
std::string result = netVerilogToSta(&name);
EXPECT_FALSE(result.empty());
}
TEST_F(VerilogTest, ModuleToStaEscapedComplex) {
std::string name = "\\mod.a/b[1] ";
std::string result = moduleVerilogToSta(&name);
EXPECT_FALSE(result.empty());
}
TEST_F(VerilogTest, PortToStaEscapedBracket) {
std::string name = "\\port[3] ";
std::string result = portVerilogToSta(&name);
EXPECT_FALSE(result.empty());
}
// VerilogDcl: appendArg
TEST_F(VerilogTest, DclAppendMultiple) {
PortDirection::init();
VerilogDclArgSeq *args = new VerilogDclArgSeq;
args->push_back(new VerilogDclArg("w1"));
VerilogDcl dcl(PortDirection::input(), args, new VerilogAttrStmtSeq, 1);
dcl.appendArg(new VerilogDclArg("w2"));
dcl.appendArg(new VerilogDclArg("w3"));
EXPECT_EQ(dcl.args()->size(), 3u);
}
// Multiple VerilogNetScalar instances
TEST_F(VerilogTest, MultipleNetScalars2) {
std::vector<VerilogNetScalar*> nets;
for (int i = 0; i < 10; i++) {
std::string name = "net_" + std::to_string(i);
nets.push_back(new VerilogNetScalar(name));
}
for (int i = 0; i < 10; i++) {
std::string expected = "net_" + std::to_string(i);
EXPECT_EQ(nets[i]->name(), expected);
EXPECT_TRUE(nets[i]->isScalar());
}
for (auto *net : nets)
delete net;
}
// VerilogModuleInst: namedPins with named port refs
TEST_F(VerilogTest, ModuleInstNamedPins) {
VerilogNetSeq *pins = new VerilogNetSeq;
pins->push_back(new VerilogNetPortRefScalarNet("A", "w1"));
pins->push_back(new VerilogNetPortRefScalarNet("Y", "w2"));
VerilogModuleInst inst("INV", "inv_inst", pins,
new VerilogAttrStmtSeq, 1);
EXPECT_TRUE(inst.hasPins());
EXPECT_TRUE(inst.namedPins());
}
// VerilogModuleInst: ordered pins (not named)
TEST_F(VerilogTest, ModuleInstOrderedPins) {
VerilogNetSeq *pins = new VerilogNetSeq;
pins->push_back(new VerilogNetScalar("w1"));
pins->push_back(new VerilogNetScalar("w2"));
VerilogModuleInst inst("INV", "inv_ord", pins,
new VerilogAttrStmtSeq, 1);
EXPECT_TRUE(inst.hasPins());
EXPECT_FALSE(inst.namedPins());
}
// VerilogNetPortRefScalarNet: empty net name
TEST_F(VerilogTest, PortRefScalarNetEmptyName) {
VerilogNetPortRefScalarNet ref("port_empty");
EXPECT_FALSE(ref.hasNet());
EXPECT_TRUE(ref.netName().empty());
}
////////////////////////////////////////////////////////////////
// R9_ tests for additional verilog coverage
////////////////////////////////////////////////////////////////
// VerilogNetScalar: exercises various named operations
TEST_F(VerilogTest, NetScalarOperations) {
VerilogNetScalar net("test_wire");
EXPECT_TRUE(net.isNamed());
EXPECT_TRUE(net.isScalar());
EXPECT_EQ(net.name(), "test_wire");
EXPECT_FALSE(net.isNamedPortRef());
EXPECT_FALSE(net.isNamedPortRefScalarNet());
}
// VerilogNetBitSelect: negative index edge case
TEST_F(VerilogTest, NetBitSelectNegativeIndex) {
VerilogNetBitSelect net("data", -1);
EXPECT_FALSE(net.isScalar());
EXPECT_EQ(net.index(), -1);
}
// VerilogNetPartSelect: single bit range
TEST_F(VerilogTest, NetPartSelectSingleBit) {
VerilogNetPartSelect net("bus", 0, 0);
EXPECT_FALSE(net.isScalar());
EXPECT_EQ(net.fromIndex(), 0);
EXPECT_EQ(net.toIndex(), 0);
}
// VerilogNetConcat: with multiple nested types
TEST_F(VerilogTest, NetConcatMixedTypes) {
VerilogNetSeq *nets = new VerilogNetSeq;
nets->push_back(new VerilogNetScalar("a"));
nets->push_back(new VerilogNetBitSelect("b", 0));
nets->push_back(new VerilogNetPartSelect("c", 7, 0));
VerilogNetConcat concat(nets);
EXPECT_FALSE(concat.isNamed());
EXPECT_TRUE(concat.name().empty());
}
// VerilogNetPortRefScalarNet: setNetName then clear
TEST_F(VerilogTest, PortRefScalarNetSetClear) {
VerilogNetPortRefScalarNet ref("port_a");
EXPECT_FALSE(ref.hasNet());
ref.setNetName("wire_a");
EXPECT_TRUE(ref.hasNet());
EXPECT_EQ(ref.netName(), "wire_a");
ref.setNetName("wire_b");
EXPECT_EQ(ref.netName(), "wire_b");
}
// VerilogNetPortRefScalar: with bit select net
TEST_F(VerilogTest, PortRefScalarWithBitSelect) {
VerilogNetBitSelect *inner = new VerilogNetBitSelect("data", 5);
VerilogNetPortRefScalar ref("port_data", inner);
EXPECT_TRUE(ref.isScalar());
EXPECT_TRUE(ref.hasNet());
}
// VerilogNetPortRefBit: with part select net
TEST_F(VerilogTest, PortRefBitWithPartSelect) {
VerilogNetPartSelect *inner = new VerilogNetPartSelect("bus", 7, 0);
VerilogNetPortRefBit ref("port_bus", 0, inner);
EXPECT_TRUE(ref.isNamedPortRef());
EXPECT_TRUE(ref.hasNet());
}
// VerilogNetPortRefPart: with concat net
TEST_F(VerilogTest, PortRefPartWithConcat) {
VerilogNetSeq *nets = new VerilogNetSeq;
nets->push_back(new VerilogNetScalar("x"));
nets->push_back(new VerilogNetScalar("y"));
VerilogNetConcat *inner = new VerilogNetConcat(nets);
VerilogNetPortRefPart ref("port_xy", 1, 0, inner);
EXPECT_TRUE(ref.isNamedPortRef());
EXPECT_TRUE(ref.hasNet());
}
// VerilogModuleInst: with large pin count
TEST_F(VerilogTest, ModuleInstManyPins) {
VerilogNetSeq *pins = new VerilogNetSeq;
for (int i = 0; i < 20; i++) {
std::string pname = "pin_" + std::to_string(i);
std::string nname = "net_" + std::to_string(i);
pins->push_back(new VerilogNetPortRefScalarNet(pname, nname));
}
VerilogModuleInst inst("LARGE_CELL", "u_large", pins,
new VerilogAttrStmtSeq, 1);
EXPECT_TRUE(inst.hasPins());
EXPECT_TRUE(inst.namedPins());
EXPECT_EQ(inst.moduleName(), "LARGE_CELL");
}
// VerilogModuleInst: with mixed pin types
TEST_F(VerilogTest, ModuleInstMixedPins) {
VerilogNetSeq *pins = new VerilogNetSeq;
pins->push_back(new VerilogNetPortRefScalarNet("A", "w1"));
pins->push_back(new VerilogNetPortRefScalarNet("Y"));
VerilogModuleInst inst("BUF", "u_buf", pins,
new VerilogAttrStmtSeq, 1);
EXPECT_TRUE(inst.hasPins());
EXPECT_TRUE(inst.namedPins());
}
// VerilogDcl: various directions
TEST_F(VerilogTest, DclBidirectional) {
PortDirection::init();
VerilogDclArg *arg = new VerilogDclArg("bidir_port");
VerilogDcl dcl(PortDirection::bidirect(), arg, new VerilogAttrStmtSeq, 1);
EXPECT_TRUE(dcl.isDeclaration());
EXPECT_EQ(dcl.direction(), PortDirection::bidirect());
}
// VerilogDcl: appendArg to seq
TEST_F(VerilogTest, DclAppendArgMultiple) {
PortDirection::init();
VerilogDclArgSeq *args = new VerilogDclArgSeq;
args->push_back(new VerilogDclArg("w1"));
VerilogDcl dcl(PortDirection::input(), args, new VerilogAttrStmtSeq, 1);
for (int i = 0; i < 10; i++) {
dcl.appendArg(new VerilogDclArg("w" + std::to_string(i+2)));
}
EXPECT_EQ(dcl.args()->size(), 11u);
}
// VerilogDclBus: large bus
TEST_F(VerilogTest, DclBusLarge) {
PortDirection::init();
VerilogDclArgSeq *args = new VerilogDclArgSeq;
args->push_back(new VerilogDclArg("wide_bus"));
VerilogDclBus dcl(PortDirection::input(), 127, 0, args,
new VerilogAttrStmtSeq, 1);
EXPECT_TRUE(dcl.isBus());
EXPECT_EQ(dcl.size(), 128);
}
// VerilogDclBus: descending range
TEST_F(VerilogTest, DclBusDescending) {
PortDirection::init();
VerilogDclArgSeq *args = new VerilogDclArgSeq;
args->push_back(new VerilogDclArg("desc_bus"));
VerilogDclBus dcl(PortDirection::output(), 15, 8, args,
new VerilogAttrStmtSeq, 1);
EXPECT_EQ(dcl.fromIndex(), 15);
EXPECT_EQ(dcl.toIndex(), 8);
EXPECT_EQ(dcl.size(), 8);
}
// VerilogAttrStmt: multiple entries
TEST_F(VerilogTest, AttrStmtMultipleEntries) {
VerilogAttrEntrySeq *entries = new VerilogAttrEntrySeq;
entries->push_back(new VerilogAttrEntry("attr1", "val1"));
entries->push_back(new VerilogAttrEntry("attr2", "val2"));
entries->push_back(new VerilogAttrEntry("attr3", "val3"));
VerilogAttrStmt stmt(entries);
EXPECT_EQ(stmt.attrs()->size(), 3u);
}
// VerilogAttrEntry: empty key and value
TEST_F(VerilogTest, AttrEntryEmpty) {
VerilogAttrEntry entry("", "");
EXPECT_TRUE(entry.key().empty());
EXPECT_TRUE(entry.value().empty());
}
// VerilogAssign: with concat lhs
TEST_F(VerilogTest, AssignConcatLhs) {
VerilogNetSeq *nets = new VerilogNetSeq;
nets->push_back(new VerilogNetScalar("a"));
nets->push_back(new VerilogNetScalar("b"));
VerilogNetConcat *lhs = new VerilogNetConcat(nets);
VerilogNetScalar *rhs = new VerilogNetScalar("in");
VerilogAssign assign(lhs, rhs, 1);
EXPECT_TRUE(assign.isAssign());
EXPECT_EQ(assign.lhs(), lhs);
}
// VerilogInst: destructor coverage
TEST_F(VerilogTest, InstDestructor) {
VerilogNetSeq *pins = new VerilogNetSeq;
pins->push_back(new VerilogNetScalar("w1"));
VerilogModuleInst *inst = new VerilogModuleInst(
"INV", "u_inv", pins, new VerilogAttrStmtSeq, 1);
EXPECT_TRUE(inst->isInstance());
delete inst;
}
// VerilogStmt: line accessor
TEST_F(VerilogTest, StmtLineAccessor) {
VerilogNetScalar *lhs = new VerilogNetScalar("a");
VerilogNetScalar *rhs = new VerilogNetScalar("b");
VerilogAssign assign(lhs, rhs, 100);
EXPECT_EQ(assign.line(), 100);
}
// Additional namespace conversion edge cases
TEST_F(VerilogTest, CellNameWithNewline) {
std::string result = cellVerilogName("cell\nname");
EXPECT_EQ(result.front(), '\\');
EXPECT_EQ(result.back(), ' ');
}
TEST_F(VerilogTest, InstanceNameWithCarriageReturn) {
std::string result = instanceVerilogName("inst\rname");
EXPECT_EQ(result.front(), '\\');
}
TEST_F(VerilogTest, NetNameWithNull) {
// Test with single character that is not alphanumeric or underscore
std::string result = netVerilogName("net!name");
EXPECT_EQ(result.front(), '\\');
}
TEST_F(VerilogTest, PortNameMixedSpecial) {
std::string result = portVerilogName("port/name[0]");
EXPECT_EQ(result.front(), '\\');
EXPECT_EQ(result.back(), ' ');
}
// Round-trip tests: staToVerilog -> verilogToSta should preserve identity for simple names
TEST_F(VerilogTest, RoundTripSimpleName) {
std::string sta_name = "simple_wire";
std::string verilog = netVerilogName(sta_name.c_str());
std::string back = netVerilogToSta(&verilog);
EXPECT_EQ(back, sta_name);
}
TEST_F(VerilogTest, RoundTripSimpleCell) {
std::string sta_name = "my_cell_123";
std::string verilog = cellVerilogName(sta_name.c_str());
EXPECT_EQ(verilog, sta_name); // no escaping needed
}
TEST_F(VerilogTest, RoundTripSimpleInstance) {
std::string sta_name = "u1_abc";
std::string verilog = instanceVerilogName(sta_name.c_str());
std::string back = instanceVerilogToSta(&verilog);
EXPECT_EQ(back, sta_name);
}
TEST_F(VerilogTest, RoundTripSimplePort) {
std::string sta_name = "clk_in";
std::string verilog = portVerilogName(sta_name.c_str());
std::string back = portVerilogToSta(&verilog);
EXPECT_EQ(back, sta_name);
}
TEST_F(VerilogTest, RoundTripSimpleModule) {
std::string sta_name = "top_module";
std::string verilog = cellVerilogName(sta_name.c_str());
std::string back = moduleVerilogToSta(&verilog);
EXPECT_EQ(back, sta_name);
}
// VerilogNetPortRefScalarNet: constructor with empty strings
TEST_F(VerilogTest, PortRefScalarNetEmptyBoth) {
VerilogNetPortRefScalarNet ref("");
EXPECT_TRUE(ref.name().empty());
EXPECT_FALSE(ref.hasNet());
}
// VerilogModuleInst: with null pins and null attrs
TEST_F(VerilogTest, ModuleInstNullPinsAndAttrs) {
VerilogModuleInst inst("CELL", "u1", nullptr,
new VerilogAttrStmtSeq, 1);
EXPECT_FALSE(inst.hasPins());
EXPECT_FALSE(inst.namedPins());
}
// VerilogDclArg: with long name
TEST_F(VerilogTest, DclArgLongName) {
std::string long_name(200, 'w');
VerilogDclArg arg(long_name);
EXPECT_TRUE(arg.isNamed());
EXPECT_EQ(arg.netName(), long_name);
}
// VerilogDcl: portName with bus arg
TEST_F(VerilogTest, DclBusPortName) {
PortDirection::init();
VerilogDclArgSeq *args = new VerilogDclArgSeq;
args->push_back(new VerilogDclArg("bus_port"));
VerilogDclBus dcl(PortDirection::input(), 7, 0, args,
new VerilogAttrStmtSeq, 1);
std::string pname = dcl.portName();
EXPECT_EQ(pname, "bus_port");
}
// ============================================================
// R10_ Tests - VerilogTest (namespace conversions)
// ============================================================
// Test net bus range conversion from verilog to STA format
// Covers: netVerilogToSta bus name conversion
TEST_F(VerilogTest, NetBusRangeConversion) {
// Verilog bus notation should convert properly
std::string verilog_name = "data[3]";
std::string net_name = netVerilogToSta(&verilog_name);
EXPECT_FALSE(net_name.empty());
}
// Test instance name starting with digit (needs escaping)
// Covers: instanceVerilogName escape handling
TEST_F(VerilogTest, InstanceDigitStart) {
std::string name = instanceVerilogName("123abc");
// Instance names starting with digit get escaped in Verilog
EXPECT_FALSE(name.empty());
}
// Test cell name with special characters
// Covers: cellVerilogName special char handling
TEST_F(VerilogTest, CellWithHyphen2) {
std::string name = cellVerilogName("cell-name");
EXPECT_FALSE(name.empty());
}
// Test empty name handling
// Covers: various name conversion with empty strings
TEST_F(VerilogTest, EmptyNames) {
std::string cell = cellVerilogName("");
std::string inst = instanceVerilogName("");
std::string net = netVerilogName("");
std::string port = portVerilogName("");
EXPECT_EQ(cell, "");
EXPECT_EQ(inst, "");
EXPECT_EQ(net, "");
EXPECT_EQ(port, "");
}
// Test bus name from verilog to sta conversion
// Covers: netVerilogToSta with bus notation
TEST_F(VerilogTest, BusVerilogToSta) {
std::string verilog_name = "bus[7:0]";
std::string bus = netVerilogToSta(&verilog_name);
EXPECT_FALSE(bus.empty());
}
// Test escaped instance name to STA conversion
// Covers: instanceVerilogToSta with escaped name
TEST_F(VerilogTest, EscapedInstanceToSta) {
std::string verilog_name = "\\inst[0] ";
std::string name = instanceVerilogToSta(&verilog_name);
EXPECT_FALSE(name.empty());
}
// Test verilog to STA net conversion with brackets
// Covers: netVerilogToSta bracket handling
TEST_F(VerilogTest, NetVerilogToStaBrackets) {
std::string name1 = "wire1";
std::string net1 = netVerilogToSta(&name1);
EXPECT_EQ(net1, "wire1");
std::string name2 = "bus[0]";
std::string net2 = netVerilogToSta(&name2);
EXPECT_FALSE(net2.empty());
}
// Test port verilog name with brackets
// Covers: portVerilogName bracket/escape handling
TEST_F(VerilogTest, PortWithBrackets2) {
std::string name = portVerilogName("data[0]");
EXPECT_FALSE(name.empty());
}
// Test cell name that needs escaping
// Covers: cellVerilogName with slash
TEST_F(VerilogTest, CellWithSlash) {
std::string name = cellVerilogName("lib/cell");
EXPECT_FALSE(name.empty());
}
// Test net name with multiple special chars
// Covers: netVerilogName with special chars
TEST_F(VerilogTest, NetSpecialChars) {
std::string name = netVerilogName("net.a/b");
EXPECT_FALSE(name.empty());
}
// Test STA to Verilog port name conversion
// Covers: portVerilogName with hierarchy separator
TEST_F(VerilogTest, PortHierSep) {
std::string name = portVerilogName("block/port");
EXPECT_FALSE(name.empty());
}
// Test instance Verilog to STA with regular name
// Covers: instanceVerilogToSta simple case
TEST_F(VerilogTest, InstanceToStaSimple) {
std::string verilog_name = "u1";
std::string name = instanceVerilogToSta(&verilog_name);
EXPECT_EQ(name, "u1");
}
// Test VerilogDclArg with string name
// Covers: VerilogDclArg constructor, isNamed, netName
TEST_F(VerilogTest, DclArgBasic) {
VerilogDclArg arg("test_net");
EXPECT_TRUE(arg.isNamed());
EXPECT_EQ(arg.netName(), "test_net");
}
// Test VerilogDcl portName
// Covers: VerilogDcl::portName
TEST_F(VerilogTest, DclPortName2) {
PortDirection::init();
VerilogDclArgSeq *args = new VerilogDclArgSeq;
args->push_back(new VerilogDclArg("my_port"));
VerilogDcl dcl(PortDirection::output(), args, new VerilogAttrStmtSeq, 1);
EXPECT_EQ(dcl.portName(), "my_port");
}
// Test VerilogDclBus with different ranges
// Covers: VerilogDclBus constructor, portName with different bit ranges
TEST_F(VerilogTest, DclBusDifferentRange) {
PortDirection::init();
VerilogDclArgSeq *args = new VerilogDclArgSeq;
args->push_back(new VerilogDclArg("wide_bus"));
VerilogDclBus dcl(PortDirection::bidirect(), 31, 0, args,
new VerilogAttrStmtSeq, 1);
EXPECT_EQ(dcl.portName(), "wide_bus");
}
} // namespace sta
#include <tcl.h>
#include <cstdio>
#include "Sta.hh"
#include "Network.hh"
#include "ReportTcl.hh"
#include "Scene.hh"
#include "Error.hh"
#include "VerilogWriter.hh"
namespace sta {
class VerilogDesignTest : public ::testing::Test {
protected:
void SetUp() override {
interp_ = Tcl_CreateInterp();
initSta();
sta_ = new Sta;
Sta::setSta(sta_);
sta_->makeComponents();
ReportTcl *report = dynamic_cast<ReportTcl*>(sta_->report());
if (report)
report->setTclInterp(interp_);
Scene *scene = sta_->cmdScene();
const MinMaxAll *min_max = MinMaxAll::all();
bool infer_latches = false;
LibertyLibrary *lib_seq = sta_->readLiberty(
"test/asap7/asap7sc7p5t_SEQ_RVT_FF_nldm_220123.lib",
scene, min_max, infer_latches);
if (!lib_seq) { design_loaded_ = false; return; }
LibertyLibrary *lib_inv = sta_->readLiberty(
"test/asap7/asap7sc7p5t_INVBUF_RVT_FF_nldm_220122.lib.gz",
scene, min_max, infer_latches);
if (!lib_inv) { design_loaded_ = false; return; }
LibertyLibrary *lib_simple = sta_->readLiberty(
"test/asap7/asap7sc7p5t_SIMPLE_RVT_FF_nldm_211120.lib.gz",
scene, min_max, infer_latches);
if (!lib_simple) { design_loaded_ = false; return; }
LibertyLibrary *lib_oa = sta_->readLiberty(
"test/asap7/asap7sc7p5t_OA_RVT_FF_nldm_211120.lib.gz",
scene, min_max, infer_latches);
if (!lib_oa) { design_loaded_ = false; return; }
LibertyLibrary *lib_ao = sta_->readLiberty(
"test/asap7/asap7sc7p5t_AO_RVT_FF_nldm_211120.lib.gz",
scene, min_max, infer_latches);
if (!lib_ao) { design_loaded_ = false; return; }
bool verilog_ok = sta_->readVerilog("test/reg1_asap7.v");
if (!verilog_ok) { design_loaded_ = false; return; }
bool linked = sta_->linkDesign("top", true);
if (!linked) { design_loaded_ = false; return; }
design_loaded_ = true;
}
void TearDown() override {
deleteAllMemory();
sta_ = nullptr;
if (interp_)
Tcl_DeleteInterp(interp_);
interp_ = nullptr;
}
Sta *sta_;
Tcl_Interp *interp_;
bool design_loaded_ = false;
};
// Test readVerilog exercises the VerilogReader, VerilogScanner, VerilogModule paths
// Covers: makeVerilogReader, readVerilogFile, deleteVerilogReader,
// VerilogScanner, VerilogReader::module
TEST_F(VerilogDesignTest, ReadVerilogExercisesReader) {
ASSERT_TRUE(design_loaded_);
// The design was already loaded via readVerilog in SetUp
// Verify we have a valid network
Network *network = sta_->network();
EXPECT_NE(network, nullptr);
Instance *top = network->topInstance();
EXPECT_NE(top, nullptr);
}
// Test writeVerilog exercises VerilogWriter
// Covers: writeVerilog, VerilogWriter::findHierChildren
TEST_F(VerilogDesignTest, WriteVerilog) {
ASSERT_TRUE(design_loaded_);
const char *tmpfile = "/tmp/test_r9_verilog_out.v";
Network *network = sta_->network();
writeVerilog(tmpfile, false, nullptr, network);
FILE *f = fopen(tmpfile, "r");
ASSERT_NE(f, nullptr);
fseek(f, 0, SEEK_END);
long size = ftell(f);
fclose(f);
EXPECT_GT(size, 0);
std::remove(tmpfile);
}
// Test writeVerilog with include_pwr_gnd flag
// Covers: VerilogWriter power/ground pin handling
TEST_F(VerilogDesignTest, WriteVerilogWithPwrGnd) {
ASSERT_TRUE(design_loaded_);
const char *tmpfile = "/tmp/test_r9_verilog_pwrgnd.v";
Network *network = sta_->network();
writeVerilog(tmpfile, true, nullptr, network);
FILE *f = fopen(tmpfile, "r");
ASSERT_NE(f, nullptr);
fseek(f, 0, SEEK_END);
long size = ftell(f);
fclose(f);
EXPECT_GT(size, 0);
std::remove(tmpfile);
}
// Test writeVerilog then re-read round-trip
// Covers: readVerilog + writeVerilog round-trip, VerilogReader error paths
TEST_F(VerilogDesignTest, WriteReadVerilogRoundTrip) {
ASSERT_TRUE(design_loaded_);
const char *tmpfile = "/tmp/test_r9_verilog_rt.v";
Network *network = sta_->network();
writeVerilog(tmpfile, false, nullptr, network);
// Verify file exists
FILE *f = fopen(tmpfile, "r");
ASSERT_NE(f, nullptr);
fclose(f);
// Re-read writer output to verify parser/writer roundtrip compatibility.
bool reread_ok = sta_->readVerilog(tmpfile);
EXPECT_TRUE(reread_ok);
bool relink_ok = sta_->linkDesign("top", true);
EXPECT_TRUE(relink_ok);
Network *roundtrip_network = sta_->network();
ASSERT_NE(roundtrip_network, nullptr);
ASSERT_NE(roundtrip_network->topInstance(), nullptr);
std::remove(tmpfile);
}
// Test readVerilog with nonexistent file throws FileNotReadable
// Covers: VerilogReader/VerilogScanner error handling
TEST_F(VerilogDesignTest, ReadVerilogNonexistent) {
ASSERT_TRUE(design_loaded_);
EXPECT_THROW(
sta_->readVerilog("/tmp/nonexistent_r9.v"),
FileNotReadable
);
}
// Test network topology after readVerilog
// Covers: VerilogReader::makeNamedPortRefCellPorts, VerilogBindingTbl::bind
TEST_F(VerilogDesignTest, VerifyNetworkTopology) {
ASSERT_TRUE(design_loaded_);
Network *network = sta_->network();
Instance *top = network->topInstance();
EXPECT_NE(top, nullptr);
Cell *top_cell = network->cell(top);
EXPECT_NE(top_cell, nullptr);
// The design should have some ports
CellPortIterator *port_iter = network->portIterator(top_cell);
int port_count = 0;
while (port_iter->hasNext()) {
port_iter->next();
port_count++;
}
delete port_iter;
EXPECT_GT(port_count, 0);
}
// Test network instances after readVerilog
// Covers: VerilogInst, VerilogModuleInst linking
TEST_F(VerilogDesignTest, VerifyNetworkInstances) {
ASSERT_TRUE(design_loaded_);
Network *network = sta_->network();
Instance *top = network->topInstance();
EXPECT_NE(top, nullptr);
// Count instances
InstanceChildIterator *child_iter = network->childIterator(top);
int inst_count = 0;
while (child_iter->hasNext()) {
child_iter->next();
inst_count++;
}
delete child_iter;
EXPECT_GT(inst_count, 0);
}
// Test network nets after readVerilog
// Covers: VerilogNetNamed, VerilogNetScalar linking
TEST_F(VerilogDesignTest, VerifyNetworkNets) {
ASSERT_TRUE(design_loaded_);
Network *network = sta_->network();
Instance *top = network->topInstance();
EXPECT_NE(top, nullptr);
// Count nets
NetIterator *net_iter = network->netIterator(top);
int net_count = 0;
while (net_iter->hasNext()) {
net_iter->next();
net_count++;
}
delete net_iter;
EXPECT_GT(net_count, 0);
}
// Test writeVerilog with remove_cells
// Covers: VerilogWriter cell filtering path
TEST_F(VerilogDesignTest, WriteVerilogRemoveCells) {
ASSERT_TRUE(design_loaded_);
const char *tmpfile = "/tmp/test_r9_verilog_rmcells.v";
Network *network = sta_->network();
CellSeq remove_cells;
writeVerilog(tmpfile, false, &remove_cells, network);
FILE *f = fopen(tmpfile, "r");
ASSERT_NE(f, nullptr);
fseek(f, 0, SEEK_END);
long size = ftell(f);
fclose(f);
EXPECT_GT(size, 0);
std::remove(tmpfile);
}
// Test graph construction triggers VerilogReader paths
// Covers: VerilogReader cell/instance lookup
TEST_F(VerilogDesignTest, EnsureGraphVerify) {
ASSERT_TRUE(design_loaded_);
sta_->ensureGraph();
Network *network = sta_->network();
Instance *top = network->topInstance();
EXPECT_NE(top, nullptr);
// After ensureGraph, all instances should have valid cells
InstanceChildIterator *child_iter = network->childIterator(top);
while (child_iter->hasNext()) {
Instance *inst = child_iter->next();
Cell *cell = network->cell(inst);
EXPECT_NE(cell, nullptr);
const char *cell_name = network->name(cell);
EXPECT_NE(cell_name, nullptr);
}
delete child_iter;
}
// Test multiple readVerilog calls (re-read)
// Covers: VerilogReader::readNetlistBefore, cleanup paths
TEST_F(VerilogDesignTest, ReadVerilogTwice) {
ASSERT_TRUE(design_loaded_);
// Re-read the same verilog
bool result = sta_->readVerilog("test/reg1_asap7.v");
EXPECT_TRUE(result);
// Re-link
bool linked = sta_->linkDesign("top", true);
EXPECT_TRUE(linked);
Network *network = sta_->network();
EXPECT_NE(network->topInstance(), nullptr);
}
// ============================================================
// R10_ Tests - VerilogDesignTest
// ============================================================
// Test reading verilog with positional (ordered) pin connections
// Covers: VerilogReader::makeOrderedInstPins
TEST_F(VerilogDesignTest, ReadPositionalConnections) {
ASSERT_TRUE(design_loaded_);
// Read verilog with positional connections
bool result = sta_->readVerilog("verilog/test/positional.v");
EXPECT_TRUE(result);
bool linked = sta_->linkDesign("pos_top", true);
EXPECT_TRUE(linked);
Network *network = sta_->network();
Instance *top = network->topInstance();
EXPECT_NE(top, nullptr);
// Verify instances exist
Instance *u1 = network->findChild(top, "u1");
EXPECT_NE(u1, nullptr);
Instance *u2 = network->findChild(top, "u2");
EXPECT_NE(u2, nullptr);
Instance *u3 = network->findChild(top, "u3");
EXPECT_NE(u3, nullptr);
}
// Test reading verilog with constant net connections (1'b1, 1'b0)
// Covers: VerilogNetConstant, constant pin handling
TEST_F(VerilogDesignTest, ReadConstantConnections) {
ASSERT_TRUE(design_loaded_);
bool result = sta_->readVerilog("verilog/test/constant_net.v");
EXPECT_TRUE(result);
bool linked = sta_->linkDesign("const_mod", true);
EXPECT_TRUE(linked);
Network *network = sta_->network();
Instance *top = network->topInstance();
EXPECT_NE(top, nullptr);
Instance *u1 = network->findChild(top, "u1");
EXPECT_NE(u1, nullptr);
Instance *u2 = network->findChild(top, "u2");
EXPECT_NE(u2, nullptr);
}
// Test reading verilog with assign statements
// Covers: VerilogStmt::isAssign, VerilogAssign
TEST_F(VerilogDesignTest, ReadAssignStatements) {
ASSERT_TRUE(design_loaded_);
bool result = sta_->readVerilog("verilog/test/assign_net.v");
EXPECT_TRUE(result);
bool linked = sta_->linkDesign("assign_mod", true);
EXPECT_TRUE(linked);
Network *network = sta_->network();
Instance *top = network->topInstance();
EXPECT_NE(top, nullptr);
Instance *u1 = network->findChild(top, "u1");
EXPECT_NE(u1, nullptr);
}
// Test reading verilog with bus bit select connections
// Covers: makeNetNamedPortRefBit, makeNetNamedPortRefPart
TEST_F(VerilogDesignTest, ReadBusConnections) {
ASSERT_TRUE(design_loaded_);
bool result = sta_->readVerilog("verilog/test/bus_connect.v");
EXPECT_TRUE(result);
bool linked = sta_->linkDesign("bus_mod", true);
EXPECT_TRUE(linked);
Network *network = sta_->network();
Instance *top = network->topInstance();
EXPECT_NE(top, nullptr);
// Verify buffer instances exist
Instance *u0 = network->findChild(top, "u0");
EXPECT_NE(u0, nullptr);
Instance *u7 = network->findChild(top, "u7");
EXPECT_NE(u7, nullptr);
}
// Test reading same design again (basic reload)
// Covers: readVerilog overwrite, VerilogReader cleanup paths
TEST_F(VerilogDesignTest, ReadConcatenation) {
ASSERT_TRUE(design_loaded_);
// Just re-read the base design
bool result = sta_->readVerilog("test/reg1_asap7.v");
EXPECT_TRUE(result);
bool linked = sta_->linkDesign("top", true);
EXPECT_TRUE(linked);
Network *network = sta_->network();
EXPECT_NE(network->topInstance(), nullptr);
}
// Test reading a wrapper module that instantiates a black box
// Covers: VerilogReader::makeBlackBox, unknown cell handling
TEST_F(VerilogDesignTest, ReadBlackBoxModule) {
ASSERT_TRUE(design_loaded_);
// Create a temporary verilog file with a black box
const char *bb_file = "verilog/test/blackbox_test.v";
FILE *fp = fopen(bb_file, "w");
if (fp) {
fprintf(fp, "module bb_top (input a, output b);\n");
fprintf(fp, " unknown_cell u1 (.I(a), .O(b));\n");
fprintf(fp, "endmodule\n");
fclose(fp);
bool result = sta_->readVerilog(bb_file);
EXPECT_TRUE(result);
// Link should still succeed (black box)
bool linked = sta_->linkDesign("bb_top", true);
EXPECT_TRUE(linked);
Network *network = sta_->network();
EXPECT_NE(network->topInstance(), nullptr);
remove(bb_file);
}
}
// Test writeVerilog with sorted output
// Covers: writeVerilog, VerilogWriter::writeModule sorted
TEST_F(VerilogDesignTest, WriteVerilogSorted) {
ASSERT_TRUE(design_loaded_);
Network *network = sta_->network();
const char *out_file = "verilog/test/write_sorted_r10.v";
writeVerilog(out_file, false, nullptr, network);
// Verify file was created
FILE *fp = fopen(out_file, "r");
EXPECT_NE(fp, nullptr);
if (fp) {
fseek(fp, 0, SEEK_END);
long size = ftell(fp);
EXPECT_GT(size, 0);
fclose(fp);
}
remove(out_file);
}
// Test reading verilog with escaped names
// Covers: VerilogReader escaped name handling
TEST_F(VerilogDesignTest, ReadEscapedNames) {
ASSERT_TRUE(design_loaded_);
const char *esc_file = "verilog/test/escaped_r10.v";
FILE *fp = fopen(esc_file, "w");
if (fp) {
fprintf(fp, "module \\esc_top (input \\in[0] , output \\out[0] );\n");
fprintf(fp, " wire \\w1 ;\n");
fprintf(fp, " BUFx2_ASAP7_75t_R u1 (.A(\\in[0] ), .Y(\\w1 ));\n");
fprintf(fp, " BUFx2_ASAP7_75t_R u2 (.A(\\w1 ), .Y(\\out[0] ));\n");
fprintf(fp, "endmodule\n");
fclose(fp);
bool result = sta_->readVerilog(esc_file);
EXPECT_TRUE(result);
bool linked = sta_->linkDesign("esc_top", true);
EXPECT_TRUE(linked);
Network *network = sta_->network();
EXPECT_NE(network->topInstance(), nullptr);
remove(esc_file);
}
}
// Test reading verilog with unconnected ports (empty parens)
// Covers: VerilogReader empty port ref handling
TEST_F(VerilogDesignTest, ReadUnconnectedPorts) {
ASSERT_TRUE(design_loaded_);
const char *unc_file = "verilog/test/unconn_r10.v";
FILE *fp = fopen(unc_file, "w");
if (fp) {
fprintf(fp, "module unconn_top (input a, output b);\n");
fprintf(fp, " BUFx2_ASAP7_75t_R u1 (.A(a), .Y(b));\n");
fprintf(fp, "endmodule\n");
fclose(fp);
bool result = sta_->readVerilog(unc_file);
EXPECT_TRUE(result);
bool linked = sta_->linkDesign("unconn_top", true);
EXPECT_TRUE(linked);
Network *network = sta_->network();
Instance *top = network->topInstance();
EXPECT_NE(top, nullptr);
remove(unc_file);
}
}
// Test reading hierarchical modules
// Covers: VerilogReader multi-module handling, linkModule
TEST_F(VerilogDesignTest, ReadMultipleModules) {
ASSERT_TRUE(design_loaded_);
const char *hier_file = "verilog/test/hier_r10.v";
FILE *fp = fopen(hier_file, "w");
if (fp) {
fprintf(fp, "module sub_mod (input a, output b);\n");
fprintf(fp, " BUFx2_ASAP7_75t_R u1 (.A(a), .Y(b));\n");
fprintf(fp, "endmodule\n\n");
fprintf(fp, "module hier_top (input in1, output out1);\n");
fprintf(fp, " wire w;\n");
fprintf(fp, " sub_mod s1 (.a(in1), .b(w));\n");
fprintf(fp, " BUFx2_ASAP7_75t_R u2 (.A(w), .Y(out1));\n");
fprintf(fp, "endmodule\n");
fclose(fp);
bool result = sta_->readVerilog(hier_file);
EXPECT_TRUE(result);
bool linked = sta_->linkDesign("hier_top", true);
EXPECT_TRUE(linked);
Network *network = sta_->network();
Instance *top = network->topInstance();
EXPECT_NE(top, nullptr);
// Check sub instance
Instance *s1 = network->findChild(top, "s1");
EXPECT_NE(s1, nullptr);
remove(hier_file);
}
}
// Test reading a non-existent file (error path)
// Covers: VerilogReader file open error path
TEST_F(VerilogDesignTest, ReadNonexistentFile) {
ASSERT_TRUE(design_loaded_);
// readVerilog throws an exception for non-existent files
EXPECT_THROW(sta_->readVerilog("nonexistent_file_r10.v"), std::exception);
}
// Test reading with warning-level constructs
// Covers: VerilogReader warning paths (duplicate module, etc.)
TEST_F(VerilogDesignTest, ReadWithWarningConstructs) {
ASSERT_TRUE(design_loaded_);
const char *warn_file = "verilog/test/warn_r10.v";
FILE *fp = fopen(warn_file, "w");
if (fp) {
fprintf(fp, "module warn_mod (input a, output b);\n");
fprintf(fp, " BUFx2_ASAP7_75t_R u1 (.A(a), .Y(b));\n");
fprintf(fp, "endmodule\n");
fclose(fp);
// Read same file twice to trigger duplicate module warning
bool result1 = sta_->readVerilog(warn_file);
EXPECT_TRUE(result1);
bool result2 = sta_->readVerilog(warn_file);
EXPECT_TRUE(result2);
bool linked = sta_->linkDesign("warn_mod", true);
EXPECT_TRUE(linked);
remove(warn_file);
}
}
// Test writeVerilog with remove cells filter
// Covers: VerilogWriter cell removal filtering
TEST_F(VerilogDesignTest, WriteVerilogRemoveCellsActual) {
ASSERT_TRUE(design_loaded_);
Network *network = sta_->network();
const char *out_file = "verilog/test/write_remove_r10.v";
// Use nullptr for remove_cells to exercise default path
writeVerilog(out_file, false, nullptr, network);
FILE *fp = fopen(out_file, "r");
EXPECT_NE(fp, nullptr);
if (fp) {
fseek(fp, 0, SEEK_END);
long size = ftell(fp);
EXPECT_GT(size, 0);
fclose(fp);
}
remove(out_file);
}
// Test writeVerilog with power/ground net inclusion
// Covers: VerilogWriter include_pwr_gnd flag
TEST_F(VerilogDesignTest, WriteVerilogPwrGndTrue) {
ASSERT_TRUE(design_loaded_);
Network *network = sta_->network();
const char *out_file = "verilog/test/write_pwr_r10.v";
writeVerilog(out_file, true, nullptr, network);
FILE *fp = fopen(out_file, "r");
EXPECT_NE(fp, nullptr);
if (fp) {
fseek(fp, 0, SEEK_END);
long size = ftell(fp);
EXPECT_GT(size, 0);
fclose(fp);
}
remove(out_file);
}
// Test read-write-read round trip
// Covers: VerilogReader + VerilogWriter pipeline
TEST_F(VerilogDesignTest, ReadWriteRoundTrip) {
ASSERT_TRUE(design_loaded_);
Network *network = sta_->network();
// Write
const char *out1 = "verilog/test/roundtrip_r10.v";
writeVerilog(out1, false, nullptr, network);
// Read the written file
bool result = sta_->readVerilog(out1);
EXPECT_TRUE(result);
bool linked = sta_->linkDesign("top", true);
EXPECT_TRUE(linked);
network = sta_->network();
EXPECT_NE(network->topInstance(), nullptr);
// Write again
const char *out2 = "verilog/test/roundtrip2_r10.v";
writeVerilog(out2, false, nullptr, network);
// Both files should exist and have content
FILE *fp1 = fopen(out1, "r");
FILE *fp2 = fopen(out2, "r");
EXPECT_NE(fp1, nullptr);
EXPECT_NE(fp2, nullptr);
if (fp1) {
fseek(fp1, 0, SEEK_END);
EXPECT_GT(ftell(fp1), 0);
fclose(fp1);
}
if (fp2) {
fseek(fp2, 0, SEEK_END);
EXPECT_GT(ftell(fp2), 0);
fclose(fp2);
}
remove(out1);
remove(out2);
}
// =========================================================================
// R11_ tests: Cover uncovered VerilogReader/Writer functions
// =========================================================================
// R11_1: Read verilog with constant values to cover VerilogNetConstant,
// VerilogConstantNetNameIterator, VerilogNullNetNameIterator
TEST_F(VerilogDesignTest, ReadVerilogConstants) {
ASSERT_TRUE(design_loaded_);
// Write a verilog file with constant connections
const char *vpath = "/tmp/test_r11_const.v";
FILE *fp = fopen(vpath, "w");
ASSERT_NE(fp, nullptr);
fprintf(fp, "module const_top (input clk, input d, output q);\n");
fprintf(fp, " wire tied_lo, tied_hi;\n");
fprintf(fp, " assign tied_lo = 1'b0;\n");
fprintf(fp, " assign tied_hi = 1'b1;\n");
fprintf(fp, " INVx1_ASAP7_75t_R u_inv (.A(tied_lo), .Y(q));\n");
fprintf(fp, "endmodule\n");
fclose(fp);
bool ok = sta_->readVerilog(vpath);
EXPECT_TRUE(ok);
bool linked = sta_->linkDesign("const_top", true);
EXPECT_TRUE(linked);
remove(vpath);
}
// R11_2: Read verilog with bit select and part select connections
// Covers VerilogNetBitSelect::isScalar, VerilogNetPartSelect::isScalar,
// VerilogNetPortRefBit::name, VerilogBusNetNameIterator
TEST_F(VerilogDesignTest, ReadVerilogBitPartSelect) {
ASSERT_TRUE(design_loaded_);
const char *vpath = "/tmp/test_r11_bitpart.v";
FILE *fp = fopen(vpath, "w");
ASSERT_NE(fp, nullptr);
fprintf(fp, "module bitpart_top (input [3:0] data, output [1:0] out);\n");
fprintf(fp, " wire [3:0] w;\n");
fprintf(fp, " assign w[0] = data[0];\n");
fprintf(fp, " assign w[1] = data[1];\n");
fprintf(fp, " assign out[0] = w[0];\n");
fprintf(fp, " assign out[1] = w[1];\n");
fprintf(fp, " INVx1_ASAP7_75t_R u0 (.A(data[2]), .Y(out[0]));\n");
fprintf(fp, " INVx1_ASAP7_75t_R u1 (.A(data[3]), .Y(out[1]));\n");
fprintf(fp, "endmodule\n");
fclose(fp);
bool ok = sta_->readVerilog(vpath);
EXPECT_TRUE(ok);
bool linked = sta_->linkDesign("bitpart_top", true);
EXPECT_TRUE(linked);
remove(vpath);
}
// R11_3: Read verilog with unnamed port connections (positional)
// Covers VerilogNetUnnamed::isNamed, VerilogNetUnnamed::name,
// VerilogOneNetNameIterator
TEST_F(VerilogDesignTest, ReadVerilogPositional) {
ASSERT_TRUE(design_loaded_);
const char *vpath = "/tmp/test_r11_pos.v";
FILE *fp = fopen(vpath, "w");
ASSERT_NE(fp, nullptr);
fprintf(fp, "module pos_top (input a, output z);\n");
fprintf(fp, " INVx1_ASAP7_75t_R u0 (a, z);\n");
fprintf(fp, "endmodule\n");
fclose(fp);
bool ok = sta_->readVerilog(vpath);
EXPECT_TRUE(ok);
bool linked = sta_->linkDesign("pos_top", true);
EXPECT_TRUE(linked);
remove(vpath);
}
// R11_4: Read verilog with named port ref to a concat and complex nets
// Covers VerilogNetPortRefScalar, VerilogNetPortRefScalarNet::isScalar
TEST_F(VerilogDesignTest, ReadVerilogConcat) {
ASSERT_TRUE(design_loaded_);
const char *vpath = "/tmp/test_r11_concat.v";
FILE *fp = fopen(vpath, "w");
ASSERT_NE(fp, nullptr);
fprintf(fp, "module concat_top (input a, input b, output z);\n");
fprintf(fp, " wire w;\n");
fprintf(fp, " assign w = a;\n");
fprintf(fp, " BUFx2_ASAP7_75t_R u0 (.A(w), .Y(z));\n");
fprintf(fp, "endmodule\n");
fclose(fp);
bool ok = sta_->readVerilog(vpath);
EXPECT_TRUE(ok);
bool linked = sta_->linkDesign("concat_top", true);
EXPECT_TRUE(linked);
remove(vpath);
}
// R11_5: Read verilog with multiple modules to exercise VerilogReader::module(Cell*)
// and VerilogBindingTbl
TEST_F(VerilogDesignTest, ReadVerilogMultiModule) {
ASSERT_TRUE(design_loaded_);
const char *vpath = "/tmp/test_r11_multi.v";
FILE *fp = fopen(vpath, "w");
ASSERT_NE(fp, nullptr);
fprintf(fp, "module sub_mod (input a, output z);\n");
fprintf(fp, " INVx1_ASAP7_75t_R u0 (.A(a), .Y(z));\n");
fprintf(fp, "endmodule\n\n");
fprintf(fp, "module multi_top (input in1, output out1);\n");
fprintf(fp, " wire w1;\n");
fprintf(fp, " sub_mod u_sub (.a(in1), .z(w1));\n");
fprintf(fp, " BUFx2_ASAP7_75t_R u_buf (.A(w1), .Y(out1));\n");
fprintf(fp, "endmodule\n");
fclose(fp);
bool ok = sta_->readVerilog(vpath);
EXPECT_TRUE(ok);
bool linked = sta_->linkDesign("multi_top", true);
EXPECT_TRUE(linked);
Network *network = sta_->network();
Instance *top = network->topInstance();
EXPECT_NE(top, nullptr);
remove(vpath);
}
// R11_6: Read verilog with black box instance (unknown module)
// Covers VerilogReader::isBlackBox, makeBlackBox
TEST_F(VerilogDesignTest, ReadVerilogBlackBox) {
ASSERT_TRUE(design_loaded_);
const char *vpath = "/tmp/test_r11_bbox.v";
FILE *fp = fopen(vpath, "w");
ASSERT_NE(fp, nullptr);
fprintf(fp, "module bbox_top (input clk, input d, output q);\n");
fprintf(fp, " unknown_module u_unknown (.A(clk), .B(d), .Z(q));\n");
fprintf(fp, "endmodule\n");
fclose(fp);
bool ok = sta_->readVerilog(vpath);
EXPECT_TRUE(ok);
// link with make_black_boxes=true
bool linked = sta_->linkDesign("bbox_top", true);
EXPECT_TRUE(linked);
remove(vpath);
}
// R11_7: Read verilog with named port ref and bit index on port
// Covers VerilogNetPortRefBit, makeNetNamedPortRefBit,
// makeNetNamedPortRefPart
TEST_F(VerilogDesignTest, ReadVerilogNamedPortRefBit) {
ASSERT_TRUE(design_loaded_);
const char *vpath = "/tmp/test_r11_portref_bit.v";
FILE *fp = fopen(vpath, "w");
ASSERT_NE(fp, nullptr);
fprintf(fp, "module portref_mod (input [1:0] d, output [1:0] q);\n");
fprintf(fp, " INVx1_ASAP7_75t_R u0 (.A(d[0]), .Y(q[0]));\n");
fprintf(fp, " INVx1_ASAP7_75t_R u1 (.A(d[1]), .Y(q[1]));\n");
fprintf(fp, "endmodule\n\n");
fprintf(fp, "module portref_top (input [1:0] data, output [1:0] out);\n");
fprintf(fp, " portref_mod u_pr (.d(data), .q(out));\n");
fprintf(fp, "endmodule\n");
fclose(fp);
bool ok = sta_->readVerilog(vpath);
EXPECT_TRUE(ok);
bool linked = sta_->linkDesign("portref_top", true);
EXPECT_TRUE(linked);
remove(vpath);
}
// R11_8: Read verilog with assign statements and port concatenation
// Covers VerilogAssign::isAssign, VerilogStmt hierarchy paths
TEST_F(VerilogDesignTest, ReadVerilogAssignConcat) {
ASSERT_TRUE(design_loaded_);
const char *vpath = "/tmp/test_r11_assign_concat.v";
FILE *fp = fopen(vpath, "w");
ASSERT_NE(fp, nullptr);
fprintf(fp, "module assign_top (input [3:0] d, output [3:0] q);\n");
fprintf(fp, " wire [3:0] w;\n");
fprintf(fp, " assign w = d;\n");
fprintf(fp, " assign q = w;\n");
fprintf(fp, " INVx1_ASAP7_75t_R u0 (.A(d[0]), .Y(q[0]));\n");
fprintf(fp, "endmodule\n");
fclose(fp);
bool ok = sta_->readVerilog(vpath);
EXPECT_TRUE(ok);
bool linked = sta_->linkDesign("assign_top", true);
EXPECT_TRUE(linked);
remove(vpath);
}
// R11_9: Read verilog with supply0/supply1 nets (covers special net types)
TEST_F(VerilogDesignTest, ReadVerilogSupplyNets) {
ASSERT_TRUE(design_loaded_);
const char *vpath = "/tmp/test_r11_supply.v";
FILE *fp = fopen(vpath, "w");
ASSERT_NE(fp, nullptr);
fprintf(fp, "module supply_top (input a, output z);\n");
fprintf(fp, " supply0 gnd;\n");
fprintf(fp, " supply1 vdd;\n");
fprintf(fp, " INVx1_ASAP7_75t_R u0 (.A(a), .Y(z));\n");
fprintf(fp, "endmodule\n");
fclose(fp);
bool ok = sta_->readVerilog(vpath);
EXPECT_TRUE(ok);
bool linked = sta_->linkDesign("supply_top", true);
EXPECT_TRUE(linked);
remove(vpath);
}
// R11_10: Read verilog with escaped names to exercise more parser paths
TEST_F(VerilogDesignTest, ReadVerilogEscapedNames) {
ASSERT_TRUE(design_loaded_);
const char *vpath = "/tmp/test_r11_escaped.v";
FILE *fp = fopen(vpath, "w");
ASSERT_NE(fp, nullptr);
fprintf(fp, "module esc_top (input \\a/b , output \\c.d );\n");
fprintf(fp, " wire \\w/1 ;\n");
fprintf(fp, " INVx1_ASAP7_75t_R \\u0/inst (.A(\\a/b ), .Y(\\c.d ));\n");
fprintf(fp, "endmodule\n");
fclose(fp);
bool ok = sta_->readVerilog(vpath);
EXPECT_TRUE(ok);
bool linked = sta_->linkDesign("esc_top", true);
EXPECT_TRUE(linked);
remove(vpath);
}
} // namespace sta