Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Enhancing verilog composer #161

Merged
merged 4 commits into from
Nov 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions spydrnet/composers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import os


def compose(netlist, filename):
def compose(netlist, filename, definition_list=[], write_blackbox=True):
"""To compose a file into a netlist format"""
extension = os.path.splitext(filename)[1]
extension_lower = extension.lower()
Expand All @@ -13,7 +13,7 @@ def compose(netlist, filename):
composer.run(netlist, filename)
elif extension_lower in [".v", ".vh"]:
from spydrnet.composers.verilog.composer import Composer
composer = Composer()
composer = Composer(definition_list, write_blackbox)
composer.run(netlist, file_out=filename)
else:
raise RuntimeError("Extension {} not recognized.".format(extension))
18 changes: 17 additions & 1 deletion spydrnet/composers/verilog/composer.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@

class Composer:

def __init__(self):
def __init__(self, definition_list=None, write_blackbox=False):
""" Write a verilog netlist from SDN netlist

parameters
----------

definition_list - (list[str]) list of defintions to write
write_blackbox - (bool) Skips writing black boxes/verilog primitives
"""
self.file = None
self.direction_string_map = dict()
self.direction_string_map[Port.Direction.IN] = "input"
Expand All @@ -15,6 +23,9 @@ def __init__(self):
self.direction_string_map[Port.Direction.UNDEFINED] = "/* undefined port direction */ inout"
self.written = set()
self.indent_count = 4 # set the indentation level for various components
self.write_blackbox = write_blackbox
self.definition_list = definition_list


def run(self, ir, file_out="out.v"):
self._open_file(file_out)
Expand Down Expand Up @@ -94,9 +105,14 @@ def _write_bundle_with_indicies(self, bundle, low, high):

def _write_module(self, definition):
'''write the constraints then the module header then the module body'''
if self.definition_list:
if not (definition.name in self.definition_list):
return
if definition.library.name == "SDN_VERILOG_ASSIGNMENT":
return # don't write assignment definitions
if definition.library.name == "SDN.verilog_primitives":
if not self.write_blackbox:
return
self.file.write(vt.CELL_DEFINE)
self.file.write(vt.NEW_LINE)
self._write_star_constraints(definition)
Expand Down
41 changes: 40 additions & 1 deletion spydrnet/composers/verilog/tests/test_composer.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,43 @@ def test_small_verilog_compose(self):

print("processed",i,"errors", errors)

assert errors == 0, "there were errors while parsing and composing files. Please see the output."
assert errors == 0, "there were errors while parsing and composing files. Please see the output."

def test_definition_list_option(self):
for filename in glob.glob(os.path.join(
self.dir_of_verilog_netlists, "*4bitadder.v.zip")):
with tempfile.TemporaryDirectory() as tempdirectory:
netlist = parsers.parse(filename)
out_file = os.path.join(
tempdirectory, os.path.basename(filename) + "-spydrnet.v")
composers.compose(netlist, out_file, definition_list=['adder'])

with open(out_file, "r") as fp:
lines = fp.readlines()
print(len(lines))
m = list(filter(lambda x: x.startswith('module'), lines))
self.assertGreater(len(m), 0, "Adder module not written")
self.assertLess(len(m), 2, "Failed to write only definition_list")
return
raise AssertionError("Adder design not found " +
"definition_list options not tested,")

def test_write_blackbox_option(self):
for filename in glob.glob(os.path.join(
self.dir_of_verilog_netlists, "*4bitadder.v.zip")):
with tempfile.TemporaryDirectory() as tempdirectory:
netlist = parsers.parse(filename)
out_file = os.path.join(
tempdirectory, os.path.basename(filename) + "-spydrnet.v")
composers.compose(netlist, out_file, write_blackbox=False)

with open(out_file, "r") as fp:
lines = fp.readlines()
print(len(lines))
m = list(filter(lambda x: x.startswith('module'), lines))
self.assertGreater(len(m), 0, "Adder module not written")
self.assertLess(len(m), 2, "Failed to write only definition_list" +
"%s" % m)
return
raise AssertionError("definition_list options not test," +
"Adder design not found")
65 changes: 33 additions & 32 deletions spydrnet/composers/verilog/tests/test_composer_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
#
#Tests the verilog composers functions and output

from collections import OrderedDict
import unittest
from unittest.case import expectedFailure
import spydrnet as sdn
from spydrnet.composers.verilog.composer import Composer

class TestVerilogComposerUnit(unittest.TestCase):

class TestFile:
'''represents a file (has a write function for the composer)
can be used as a drop in replacement for the composer file.write function
Expand All @@ -20,7 +21,7 @@ def __init__(self):

def write(self, text):
self.written += text

def clear(self):
self.written = ""

Expand All @@ -45,7 +46,7 @@ def initialize_tests(self):
composer = Composer()
composer.file = self.TestFile()
return composer

def initialize_netlist(self):
netlist = sdn.Netlist()
netlist.name = "test_netlist"
Expand All @@ -64,7 +65,7 @@ def initialize_definition(self):
return definition

def initialize_instance_parameters(self, instance):
instance["VERILOG.Parameters"] = dict()
instance["VERILOG.Parameters"] = OrderedDict()
instance["VERILOG.Parameters"]["key"] = "value"
instance["VERILOG.Parameters"]["key2"] = "value2"

Expand All @@ -82,13 +83,13 @@ def initialize_instance_port_connections(self, instance, definition):
single_bit_port.create_pin()
single_bit_port.is_downto = True
single_bit_port.name = "single_bit_port"

single_bit_cable = definition.create_cable()
single_bit_cable.name = "single_bit_cable"
single_bit_cable.is_downto = True
single_bit_cable.create_wire()


multi_bit_port = ref_def.create_port()
multi_bit_port.is_downto = True
multi_bit_port.create_pins(4)
Expand All @@ -109,7 +110,7 @@ def initialize_instance_port_connections(self, instance, definition):
multi_bit_cable.create_wires(4)
multi_bit_cable.name = "multi_bit_cable"
multi_bit_cable.is_downto = True


concatenated_port = ref_def.create_port()
concatenated_port.create_pins(4)
Expand All @@ -122,7 +123,7 @@ def initialize_instance_port_connections(self, instance, definition):
cable.is_downto = True
cable.name = "cc_" + str(i)
ccs.append(cable)


single_bit_cable.wires[0].connect_pin(instance.pins[single_bit_port.pins[0]])

Expand All @@ -135,9 +136,9 @@ def initialize_instance_port_connections(self, instance, definition):
multi_bit_cable.wires[i].connect_pin(instance.pins[partial_port.pins[i]])

single_bit_expected = "." + single_bit_port.name + "(" + single_bit_cable.name + ")"

multi_bit_expected = "." + multi_bit_port.name + "(" + multi_bit_cable.name + ")"

offset_expected = "." + multi_bit_port_offset.name + "(" + multi_bit_cable.name + ")"

partial_expected = "." + partial_port.name + "(" + multi_bit_cable.name + "[1:0])"
Expand All @@ -160,13 +161,13 @@ def test_write_header(self):
def test_write_brackets_single_bit(self):
#def _write_brackets(self, bundle, low_index, high_index):
composer = self.initialize_tests()

port = sdn.Port()
cable = sdn.Cable()

cable_name = "my_cable"
port_name = "my_port"

port.name = port_name
cable.name = cable_name

Expand Down Expand Up @@ -199,17 +200,17 @@ def test_write_brackets_single_bit(self):
assert composer.file.compare("")
composer.file.clear()
#none of these should write because they are all single bit.

def test_write_brackets_single_bit_offset(self):
#def _write_brackets(self, bundle, low_index, high_index):
composer = self.initialize_tests()

port = sdn.Port()
cable = sdn.Cable()

cable_name = "my_cable"
port_name = "my_port"

port.name = port_name
cable.name = cable_name

Expand Down Expand Up @@ -245,16 +246,16 @@ def test_write_brackets_single_bit_offset(self):
assert composer.file.compare("")
composer.file.clear()
#none of these should write because they are all single bit.

def test_write_brackets_multi_bit(self):
composer = self.initialize_tests()

port = sdn.Port()
cable = sdn.Cable()

cable_name = "my_cable"
port_name = "my_port"

port.name = port_name
cable.name = cable_name

Expand Down Expand Up @@ -300,17 +301,17 @@ def test_write_brackets_multi_bit(self):
composer._write_brackets(cable, 1, 2)
assert composer.file.compare("[2:1]")
composer.file.clear()


def test_write_brackets_multi_bit_offset(self):
composer = self.initialize_tests()

port = sdn.Port()
cable = sdn.Cable()

cable_name = "my_cable"
port_name = "my_port"

port.name = port_name
cable.name = cable_name

Expand Down Expand Up @@ -363,7 +364,7 @@ def test_write_brackets_fail(self):
pass #we should add some tests to test out of bounds on the brackets.

def test_write_brackets_defining(self):

composer = self.initialize_tests()

def initialize_bundle(bundle, offset, width):
Expand Down Expand Up @@ -391,7 +392,7 @@ def initialize_bundle(bundle, offset, width):
composer._write_brackets_defining(b3)
assert composer.file.compare("[3:0]")
composer.file.clear()

composer._write_brackets_defining(b4)
assert composer.file.compare("[7:4]")
composer.file.clear()
Expand All @@ -405,17 +406,17 @@ def test_write_name(self):
composer._write_name(o)
assert composer.file.compare(n)
composer.file.clear()

@unittest.expectedFailure
def test_write_none_name(self):
composer = self.initialize_tests()
o = sdn.Cable()
o = sdn.Cable()
composer._write_name(o)

@unittest.expectedFailure
def test_write_invalid_name(self):
composer = self.initialize_tests()
o = sdn.Cable()
o = sdn.Cable()
o.name = "\\escaped_no_space"
composer._write_name(o)

Expand All @@ -435,11 +436,11 @@ def test_write_instance_port(self):
composer._write_instance_port(instance, single_bit_port)
assert composer.file.compare(single_bit_expected)
composer.file.clear()

composer._write_instance_port(instance, multi_bit_port)
assert composer.file.compare(multi_bit_expected)
composer.file.clear()

composer._write_instance_port(instance, multi_bit_port_offset)
assert composer.file.compare(offset_expected)
composer.file.clear()
Expand Down Expand Up @@ -529,8 +530,8 @@ def test_write_full_instance(self):
def test_write_module_header(self):
composer = self.initialize_tests()
definition = self.initialize_definition()
definition["VERILOG.Parameters"] = dict()

definition["VERILOG.Parameters"] = OrderedDict()

definition["VERILOG.Parameters"]["key"] = "value"
definition["VERILOG.Parameters"]["no_default"] = None
Expand Down Expand Up @@ -604,7 +605,7 @@ def test_write_module_ports_header_and_body_disconnect(self):
port_disconnect = definition.create_port("disconnected")
port_disconnect.direction = sdn.Port.Direction.INOUT
port_disconnect.create_pin()

composer._write_module_header_port(port_disconnect)
assert composer.file.compare(port_disconnect.name)
composer.file.clear()
Expand All @@ -618,7 +619,7 @@ def test_write_module_body_cables(self):

cable = definition.create_cable(name = "test_cable", is_downto = True)
cable.create_wires(4)

composer._write_module_body_cable(cable)
assert composer.file.compare("wire [3:0]" + cable.name + ";\n")

Expand Down
7 changes: 3 additions & 4 deletions spydrnet/parsers/verilog/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,7 @@ def parse_instantiation(self, properties):

def parse_defparam_parameters(self):
'''parse a defparam structure and add the parameters to the associated instance

this looks like:

defparam \\avs_s1_readdata[12]~output .bus_hold = "false"; //single backslash to escape name
Expand Down Expand Up @@ -710,7 +710,7 @@ def parse_defparam_parameters(self):
token = self.next_token()
assert token == vt.SEMI_COLON, self.error_string(vt.SEMI_COLON, "to end the defparam statement", token)
self.set_instance_parameters(instance, params)


def parse_parameter_mapping(self):
params = dict()
Expand Down Expand Up @@ -776,7 +776,6 @@ def parse_port_map_single(self):
vt.DOT, "to start a port mapping instance", token)

token = self.next_token()
print(token)
assert vt.is_valid_identifier(token), self.error_string(
"valid port identifier", "for port in instantiation port map", token)
port_name = token
Expand Down Expand Up @@ -834,7 +833,7 @@ def parse_assign(self):
def parse_variable_instantiation(self):
'''parse the cable name and its indicies if any
if we are in Intel land then 2 other things can happen.
the "cable" is a constant,
the "cable" is a constant,
attach it to the \\<const0> or \\<const1> cable.
the cable is inverted,
create a new cable and an inverter block similar to the assign but with an inversion in the block
Expand Down