Skip to content

Instantly share code, notes, and snippets.

@gaurishg
Last active August 29, 2020 16:04
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gaurishg/b788d4c13cbc02b324270e9b55f5d74d to your computer and use it in GitHub Desktop.
Save gaurishg/b788d4c13cbc02b324270e9b55f5d74d to your computer and use it in GitHub Desktop.
Python3 script for counting number of NAND gates used in implementation of various logic gates and circuites in nand2tetris course.
#!/usr/bin/python3
import sys, os
import typing
args = sys.argv
# print(args)
# This dict will contain data of gate
GateDict = {"Nand": [1, {"Nand": 1}],
"DFF": [4, {"Nand": 4}],
"Screen": [0, {"Nand": 0}]}
HDLs: typing.Dict[str, str] = {} # Dict of Gates and their HDL files
dirs = ['01', '02', os.path.join('03', 'a'), os.path.join('03', 'b'),
'04', '05', '06', '07', '08', '09', '10', '11', '12', '13', ]
for folder in dirs:
folder = os.path.join('.', folder)
for f in os.listdir(folder):
if os.path.isfile(os.path.join(folder, f)):
# print("{} is file".format(f))
if f.endswith('.hdl'):
chip = f[:f.find('.hdl')]
if chip not in HDLs:
HDLs[chip] = os.path.join(folder, f)
# print(HDLs)
# Get chip name
# Get all intermediate chip names
# Repeat this procedure for all intermediate chips
def chipCount(chipName):
chipsUsed = {}
Nands = 0
if chipName in GateDict:
return GateDict[chipName]
if chipName in HDLs:
filename = HDLs[chipName]
with open(filename) as hdl_file:
comment = False
for line in hdl_file:
line = line.strip()
# Handle multiline comments
if comment:
if line.endswith("*/"):
comment = False
continue
else:
if line.startswith("/*"):
comment = True
continue
# Multiline comments handling ended
if len(line) and line[0].isupper() and line.find('(') != -1:
subChipName = line[:line.find('(')]
if subChipName in chipsUsed:
chipsUsed[subChipName] += 1
else:
chipsUsed[subChipName] = 1
for subChip in chipsUsed:
Nands_in_chip, _ = chipCount(subChip)
Nands += Nands_in_chip * chipsUsed[subChip]
GateDict[chipName] = [Nands, chipsUsed]
return Nands, chipsUsed
else:
print(chipName, "not found")
def getAllChips(chipName):
if chipName == "Nand":
return ["Nand"]
if chipName not in GateDict:
chipCount(chipName)
chips = [chipName]
chips += [chip for chip in GateDict[chipName][1]]
for chip in chips[1:]:
subchips = getAllChips(chip)
for subchip in subchips:
if subchip not in chips:
chips.append(subchip)
chips.sort(key=lambda x: GateDict[x][0], reverse=True)
return chips
def print_detailed_one(chipName):
chipsUsed = 0
if chipName not in GateDict:
chipCount(chipName)
gates = GateDict[chipName][1]
print(f"{chipName}".center(60, "="))
print(f"Chip".ljust(25) + "NANDs/chip".ljust(15) + "Total NANDs".rjust(20))
print("-" * 60)
for gate in gates:
chipsUsed+=gates[gate]
print(f"{gate}({gates[gate]})".ljust(25) + f"{GateDict[gate][0]} NANDs/chip".ljust(15) + f"{gates[gate] * GateDict[gate][0]}".rjust(20))
print("-" * 60)
print(f"Total {chipsUsed} chip{'s' if chipsUsed > 1 else ''} used".ljust(50) + f"{GateDict[chipName][0]:10}")
def print_detailed_full(chipName):
if chipName not in GateDict:
chipCount(chipName)
gates = getAllChips(chipName)
for gate in gates:
print_detailed_one(gate)
print()
def print_detailed_one_table(chipName):
gates = getAllChips(chipName)
for gate in gates:
print("{:20} {:>15} NANDs".format(gate, GateDict[gate][0]))
if len(args) > 1:
if len(args) == 2:
if args[1] in HDLs:
chipCount(args[1])
print("{:10} {:>20} NANDs".format(args[1], GateDict[args[1]][0]))
else:
print("{}.hdl not found!!".format(args[1]))
if len(args) > 2:
if args[-1] == "--full-detail":
for arg in args[1:-1]:
if arg in HDLs:
chipCount(arg)
print("PRINTING DETAILED OUTPUT FOR {}".format(arg))
print_detailed_full(arg)
else:
print("{}.hdl not found!!".format(arg))
print("X" * 60)
print("\n")
elif args[-1] == "--one-table":
for arg in args[1:-1]:
if arg in HDLs:
chipCount(arg)
print("REPORT FOR {}".format(arg))
print_detailed_one_table(arg)
else:
print("{}.hdl not found!!".format(arg))
print("X" * 60)
print("\n")
elif args[-1] == "--detailed":
for arg in args[1:-1]:
if arg in HDLs:
chipCount(arg)
print("PRINTING OUTPUT FOR {}".format(arg))
print_detailed_one(arg)
else:
print("{}.hdl not found!!")
print("X" * 60)
print("\n")
else:
for arg in args[1:]:
if arg in HDLs:
chipCount(arg)
print("{:10} {:>20} NANDs".format(arg, GateDict[arg][0]))
else:
print("{}.hdl not found".format(arg))
else:
print("Usage:")
print("Windows: python .\\NANDcounter_improved.py <Gate1> [<Gate2> ... <GateN>] [options]")
print("Linux/Mac: python3 ./NANDcounter_improved.py <Gate1> [<Gate2>...<GateN>] [options]")
print("Options:")
print("\t1. --full-detail:\t Recursively give NAND gate used in chips")
print("\t2. --one-table:\t\t All Gates used in your implementation (upto NAND itself)")
print("\t3. --detailed:\t\t Prints only first table of --full-detail")
print()
print("Example:")
print("\tLinux:\t python3 ./NANDcounter_improved.py Xor ALU Nand HalfAdder --one-table")
print("\tWindows:\t python .\\NANDcounter_improved.py Xor ALU Nand HalfAdder --one-table")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment