From 87380a4801d4c73341b64dadd0d100d178bb2199 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Sun, 13 Jan 2019 14:34:46 -0800 Subject: [PATCH 01/44] complete log file generation --- compiler/debug.py | 31 +++++++++++++++++++++++++++++ compiler/globals.py | 48 ++++++++++++++++++++++----------------------- compiler/openram.py | 9 +++++---- compiler/sram.py | 20 +++++++++---------- 4 files changed, 70 insertions(+), 38 deletions(-) diff --git a/compiler/debug.py b/compiler/debug.py index 1bf46db0..ea5eb45c 100644 --- a/compiler/debug.py +++ b/compiler/debug.py @@ -14,20 +14,51 @@ def check(check,str): index) = inspect.getouterframes(inspect.currentframe())[1] if not check: sys.stderr.write("ERROR: file {0}: line {1}: {2}\n".format(os.path.basename(filename),line_number,str)) + log("ERROR: file {0}: line {1}: {2}\n".format(os.path.basename(filename),line_number,str)) + assert 0 def error(str,return_value=0): (frame, filename, line_number, function_name, lines, index) = inspect.getouterframes(inspect.currentframe())[1] sys.stderr.write("ERROR: file {0}: line {1}: {2}\n".format(os.path.basename(filename),line_number,str)) + log("ERROR: file {0}: line {1}: {2}\n".format(os.path.basename(filename),line_number,str)) + assert return_value==0 def warning(str): (frame, filename, line_number, function_name, lines, index) = inspect.getouterframes(inspect.currentframe())[1] sys.stderr.write("WARNING: file {0}: line {1}: {2}\n".format(os.path.basename(filename),line_number,str)) + log("WARNING: file {0}: line {1}: {2}\n".format(os.path.basename(filename),line_number,str)) + +def print_raw(str): + print(str) + log(str) + + +def log(str): + try: + if log.create_file: + compile_log = open(globals.OPTS.output_path + globals.OPTS.output_name + '.log',"w+") + log.create_file = 0 + else: + compile_log = open(globals.OPTS.output_path + globals.OPTS.output_name + '.log',"a") + + if len(log.setup_output) != 0: + for line in log.setup_output: + compile_log.write(line) + log.setup_output = [] + compile_log.write(str + '\n') + except: + log.setup_out.append(str + "\n") + +#use a static list of strings to store messages until the global paths are set up +log.setup_output = [] +log.create_file = 1 + def info(lev, str): from globals import OPTS if (OPTS.debug_level >= lev): diff --git a/compiler/globals.py b/compiler/globals.py index a6360e24..f5c36551 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -71,26 +71,26 @@ def print_banner(): if OPTS.is_unit_test: return - print("|==============================================================================|") + debug.print_raw("|==============================================================================|") name = "OpenRAM Compiler" - print("|=========" + name.center(60) + "=========|") - print("|=========" + " ".center(60) + "=========|") - print("|=========" + "VLSI Design and Automation Lab".center(60) + "=========|") - print("|=========" + "Computer Science and Engineering Department".center(60) + "=========|") - print("|=========" + "University of California Santa Cruz".center(60) + "=========|") - print("|=========" + " ".center(60) + "=========|") - print("|=========" + "VLSI Computer Architecture Research Group".center(60) + "=========|") - print("|=========" + "Electrical and Computer Engineering Department".center(60) + "=========|") - print("|=========" + "Oklahoma State University".center(60) + "=========|") - print("|=========" + " ".center(60) + "=========|") + debug.print_raw("|=========" + name.center(60) + "=========|") + debug.print_raw("|=========" + " ".center(60) + "=========|") + debug.print_raw("|=========" + "VLSI Design and Automation Lab".center(60) + "=========|") + debug.print_raw("|=========" + "Computer Science and Engineering Department".center(60) + "=========|") + debug.print_raw("|=========" + "University of California Santa Cruz".center(60) + "=========|") + debug.print_raw("|=========" + " ".center(60) + "=========|") + debug.print_raw("|=========" + "VLSI Computer Architecture Research Group".center(60) + "=========|") + debug.print_raw("|=========" + "Electrical and Computer Engineering Department".center(60) + "=========|") + debug.print_raw("|=========" + "Oklahoma State University".center(60) + "=========|") + debug.print_raw("|=========" + " ".center(60) + "=========|") user_info = "Usage help: openram-user-group@ucsc.edu" - print("|=========" + user_info.center(60) + "=========|") + debug.print_raw("|=========" + user_info.center(60) + "=========|") dev_info = "Development help: openram-dev-group@ucsc.edu" - print("|=========" + dev_info.center(60) + "=========|") + debug.print_raw("|=========" + dev_info.center(60) + "=========|") temp_info = "Temp dir: {}".format(OPTS.openram_temp) - print("|=========" + temp_info.center(60) + "=========|") - print("|=========" + "See LICENSE for license info".center(60) + "=========|") - print("|==============================================================================|") + debug.print_raw("|=========" + temp_info.center(60) + "=========|") + debug.print_raw("|=========" + "See LICENSE for license info".center(60) + "=========|") + debug.print_raw("|==============================================================================|") def check_versions(): @@ -397,7 +397,7 @@ def print_time(name, now_time, last_time=None, indentation=2): time = str(round((now_time-last_time).total_seconds(),1)) + " seconds" else: time = now_time.strftime('%m/%d/%Y %H:%M:%S') - print("{0} {1}: {2}".format("*"*indentation,name,time)) + debug.print_raw("{0} {1}: {2}".format("*"*indentation,name,time)) def report_status(): @@ -413,20 +413,20 @@ def report_status(): if not OPTS.tech_name: debug.error("Tech name must be specified in config file.") - print("Technology: {0}".format(OPTS.tech_name)) - print("Total size: {} bits".format(OPTS.word_size*OPTS.num_words*OPTS.num_banks)) - print("Word size: {0}\nWords: {1}\nBanks: {2}".format(OPTS.word_size, + debug.print_raw("Technology: {0}".format(OPTS.tech_name)) + debug.print_raw("Total size: {} bits".format(OPTS.word_size*OPTS.num_words*OPTS.num_banks)) + debug.print_raw("Word size: {0}\nWords: {1}\nBanks: {2}".format(OPTS.word_size, OPTS.num_words, OPTS.num_banks)) - print("RW ports: {0}\nR-only ports: {1}\nW-only ports: {2}".format(OPTS.num_rw_ports, + debug.print_raw("RW ports: {0}\nR-only ports: {1}\nW-only ports: {2}".format(OPTS.num_rw_ports, OPTS.num_r_ports, OPTS.num_w_ports)) if OPTS.netlist_only: - print("Netlist only mode (no physical design is being done).") + debug.print_raw("Netlist only mode (no physical design is being done).") if not OPTS.inline_lvsdrc: - print("DRC/LVS/PEX is only run on the top-level design.") + debug.print_raw("DRC/LVS/PEX is only run on the top-level design.") if not OPTS.check_lvsdrc: - print("DRC/LVS/PEX is completely disabled.") + debug.print_raw("DRC/LVS/PEX is completely disabled.") diff --git a/compiler/openram.py b/compiler/openram.py index 78241f6a..0fe3f7cd 100755 --- a/compiler/openram.py +++ b/compiler/openram.py @@ -44,15 +44,16 @@ from sram_config import sram_config # Configure the SRAM organization c = sram_config(word_size=OPTS.word_size, num_words=OPTS.num_words) -print("Words per row: {}".format(c.words_per_row)) +debug.print_raw("Words per row: {}".format(c.words_per_row)) #from parser import * -output_extensions = ["sp","v","lib","py","html"] +output_extensions = ["sp","v","lib","py","html","log"] if not OPTS.netlist_only: output_extensions.extend(["gds","lef"]) output_files = ["{0}{1}.{2}".format(OPTS.output_path,OPTS.output_name,x) for x in output_extensions] -print("Output files are: ") -print(*output_files,sep="\n") +debug.print_raw("Output files are: ") +for path in output_files: + debug.print_raw(path) from sram import sram diff --git a/compiler/sram.py b/compiler/sram.py index 4971de08..a929434e 100644 --- a/compiler/sram.py +++ b/compiler/sram.py @@ -65,21 +65,21 @@ class sram(): # Write the layout start_time = datetime.datetime.now() gdsname = OPTS.output_path + self.s.name + ".gds" - print("GDS: Writing to {0}".format(gdsname)) + debug.print_raw("GDS: Writing to {0}".format(gdsname)) self.gds_write(gdsname) print_time("GDS", datetime.datetime.now(), start_time) # Create a LEF physical model start_time = datetime.datetime.now() lefname = OPTS.output_path + self.s.name + ".lef" - print("LEF: Writing to {0}".format(lefname)) + debug.print_raw("LEF: Writing to {0}".format(lefname)) self.lef_write(lefname) print_time("LEF", datetime.datetime.now(), start_time) # Save the spice file start_time = datetime.datetime.now() spname = OPTS.output_path + self.s.name + ".sp" - print("SP: Writing to {0}".format(spname)) + debug.print_raw("SP: Writing to {0}".format(spname)) self.sp_write(spname) print_time("Spice writing", datetime.datetime.now(), start_time) @@ -98,14 +98,14 @@ class sram(): # Characterize the design start_time = datetime.datetime.now() from characterizer import lib - print("LIB: Characterizing... ") + debug.print_raw("LIB: Characterizing... ") if OPTS.analytical_delay: - print("Using analytical delay models (no characterization)") + debug.print_raw("Using analytical delay models (no characterization)") else: if OPTS.spice_name!="": - print("Performing simulation-based characterization with {}".format(OPTS.spice_name)) + debug.print_raw("Performing simulation-based characterization with {}".format(OPTS.spice_name)) if OPTS.trim_netlist: - print("Trimming netlist to speed up characterization.") + debug.print_raw("Trimming netlist to speed up characterization.") lib(out_dir=OPTS.output_path, sram=self.s, sp_file=sp_file) print_time("Characterization", datetime.datetime.now(), start_time) @@ -114,20 +114,20 @@ class sram(): start_time = datetime.datetime.now() from shutil import copyfile copyfile(OPTS.config_file + '.py', OPTS.output_path + OPTS.output_name + '.py') - print("Config: Writing to {0}".format(OPTS.output_path + OPTS.output_name + '.py')) + debug.print_raw("Config: Writing to {0}".format(OPTS.output_path + OPTS.output_name + '.py')) print_time("Config", datetime.datetime.now(), start_time) # Write the datasheet start_time = datetime.datetime.now() from datasheet_gen import datasheet_gen dname = OPTS.output_path + self.s.name + ".html" - print("Datasheet: Writing to {0}".format(dname)) + debug.print_raw("Datasheet: Writing to {0}".format(dname)) datasheet_gen.datasheet_write(self.s,dname) print_time("Datasheet", datetime.datetime.now(), start_time) # Write a verilog model start_time = datetime.datetime.now() vname = OPTS.output_path + self.s.name + ".v" - print("Verilog: Writing to {0}".format(vname)) + debug.print_raw("Verilog: Writing to {0}".format(vname)) self.verilog_write(vname) print_time("Verilog", datetime.datetime.now(), start_time) From b66c53a99a867cd78ac42f51979a2a318fed1cea Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Sun, 13 Jan 2019 15:02:13 -0800 Subject: [PATCH 02/44] added log file to datasheet --- compiler/datasheet/datasheet_gen.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/datasheet/datasheet_gen.py b/compiler/datasheet/datasheet_gen.py index db03216b..9fcf921f 100644 --- a/compiler/datasheet/datasheet_gen.py +++ b/compiler/datasheet/datasheet_gen.py @@ -491,11 +491,12 @@ def parse_characterizer_csv(sram,f,pages): new_sheet.dlv_table.add_row(['.lef','LEF files','{0}.{1}'.format(OPTS.output_name,'lef')]) - new_sheet.dlv_table.add_row(['.sp','SPICE netlists','{0}.{1}'.format(OPTS.output_name,'sp')]) + new_sheet.dlv_table.add_row(['.log','OpenRAM compile log','{0}.{1}'.format(OPTS.output_name,'log')]) new_sheet.dlv_table.add_row(['.v','Verilog simulation models','{0}.{1}'.format(OPTS.output_name,'v')]) new_sheet.dlv_table.add_row(['.html','This datasheet','{0}.{1}'.format(OPTS.output_name,'html')]) new_sheet.dlv_table.add_row(['.lib','Synthesis models','{1}'.format(LIB_NAME,LIB_NAME.replace(OUT_DIR,''))]) new_sheet.dlv_table.add_row(['.py','OpenRAM configuration file','{0}.{1}'.format(OPTS.output_name,'py')]) + new_sheet.dlv_table.add_row(['.sp','SPICE netlists','{0}.{1}'.format(OPTS.output_name,'sp')]) new_sheet.io_table.add_row(['WORD_SIZE',WORD_SIZE]) new_sheet.io_table.add_row(['NUM_WORDS',NUM_WORDS]) From 903cafb3362a940906dc47c399a4189b8ae650e2 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Tue, 15 Jan 2019 19:47:48 -0800 Subject: [PATCH 03/44] html parsing finished --- compiler/datasheet/datasheet.py | 54 ++-- compiler/datasheet/datasheet_gen.py | 266 ++++++++++-------- .../datasheet/library_page/lib_table_gen.py | 43 +++ compiler/datasheet/library_page/library.py | 16 ++ .../datasheet/library_page/library_gen.py | 60 ++++ 5 files changed, 287 insertions(+), 152 deletions(-) create mode 100644 compiler/datasheet/library_page/lib_table_gen.py create mode 100644 compiler/datasheet/library_page/library.py create mode 100644 compiler/datasheet/library_page/library_gen.py diff --git a/compiler/datasheet/datasheet.py b/compiler/datasheet/datasheet.py index ce84c22c..566dfc80 100644 --- a/compiler/datasheet/datasheet.py +++ b/compiler/datasheet/datasheet.py @@ -4,59 +4,60 @@ import csv import base64 from globals import OPTS + class datasheet(): """ Defines the layout,but not the data, of the html datasheet """ - def __init__(self,identifier): + + def __init__(self, identifier): self.name = identifier self.html = "" - def generate_html(self): """ Generates html tables using flask-table """ with open(os.path.abspath(os.environ.get("OPENRAM_HOME")) + '/datasheet/assets/datasheet.css', 'r') as datasheet_css: - #css styling is kept in a seperate file + # css styling is kept in a seperate file self.html += datasheet_css.read() - -# with open(OPTS.openram_temp + "/datasheet.info") as info: + +# with open(OPTS.openram_temp + "/datasheet.info") as info: self.html += '' - + self.html += '-->' + vlsi_logo = 0 - with open(os.path.abspath(os.environ.get("OPENRAM_HOME")) + '/datasheet/assets/vlsi_logo.png' , "rb") as image_file: + with open(os.path.abspath(os.environ.get("OPENRAM_HOME")) + '/datasheet/assets/vlsi_logo.png', "rb") as image_file: vlsi_logo = base64.b64encode(image_file.read()) openram_logo = 0 - with open(os.path.abspath(os.environ.get("OPENRAM_HOME")) + '/datasheet/assets/openram_logo_placeholder.png' , "rb") as image_file: + with open(os.path.abspath(os.environ.get("OPENRAM_HOME")) + '/datasheet/assets/openram_logo_placeholder.png', "rb") as image_file: openram_logo = base64.b64encode(image_file.read()) + self.html += 'VLSIDA'.format(str(vlsi_logo)[ + 2:-1]) - self.html += 'VLSIDA'.format(str(vlsi_logo)[2:-1]) - + self.html += '

' + \ + self.name + '.html' + '

' + self.html += '

Compiled at: ' + self.time + '

' + self.html += '

' + \ + 'DRC errors: ' + str(self.DRC) + '

' + self.html += '

' + \ + 'LVS errors: ' + str(self.LVS) + '

' + self.html += '

' + \ + 'Git commit id: ' + str(self.git_id) + '

' - - - - self.html +='

'+ self.name + '.html' + '

' - self.html +='

Compiled at: '+ self.time + '

' - self.html +='

'+ 'DRC errors: ' + str(self.DRC) + '

' - self.html +='

'+ 'LVS errors: ' + str(self.LVS) + '

' - self.html += '

'+ 'Git commit id: ' + str(self.git_id) + '

' - - self.html +='

Ports and Configuration

' + self.html += '

Ports and Configuration

' # self.html += in_out(self.io,table_id='data').__html__().replace('<','<').replace('"','"').replace('>',">") self.html += self.io_table.to_html() - - self.html +='

Operating Conditions

' + + self.html += '

Operating Conditions

' # self.html += operating_conditions(self.operating,table_id='data').__html__() self.html += self.operating_table.to_html() @@ -68,9 +69,6 @@ class datasheet(): # self.html += characterization_corners(self.corners,table_id='data').__html__() self.html += self.corners_table.to_html() - self.html +='

Deliverables

' + self.html += '

Deliverables

' # self.html += deliverables(self.dlv,table_id='data').__html__().replace('<','<').replace('"','"').replace('>',">") self.html += self.dlv_table.to_html() - - - diff --git a/compiler/datasheet/datasheet_gen.py b/compiler/datasheet/datasheet_gen.py index 9fcf921f..93ab783c 100644 --- a/compiler/datasheet/datasheet_gen.py +++ b/compiler/datasheet/datasheet_gen.py @@ -1,21 +1,21 @@ #!/usr/bin/env python3 """ -This is a script to load data from the characterization and layout processes into +This is a script to load data from the characterization and layout processes into a web friendly html datasheet. """ -#TODO: -#include log file -#Diagram generation -#Improve css +# TODO: +# include log file +# Diagram generation +# Improve css -import debug from globals import OPTS -import os, math -import optparse +import os +import math import csv -from datasheet import * -from table_gen import * +import datasheet +import table_gen + def process_name(corner): """ @@ -30,20 +30,20 @@ def process_name(corner): else: return "custom" -def parse_characterizer_csv(sram,f,pages): + +def parse_characterizer_csv(sram, f, pages): """ Parses output data of the Liberty file generator in order to construct the timing and current table """ with open(f) as csv_file: csv_reader = csv.reader(csv_file, delimiter=',') - line_count = 0 for row in csv_reader: found = 0 col = 0 - #defines layout of csv file + # defines layout of csv file NAME = row[col] col += 1 @@ -85,29 +85,28 @@ def parse_characterizer_csv(sram,f,pages): WORD_SIZE = row[col] col += 1 - + ORIGIN_ID = row[col] col += 1 DATETIME = row[col] - col+= 1 + col += 1 DRC = row[col] col += 1 LVS = row[col] col += 1 - - for sheet in pages: + for sheet in pages: if sheet.name == NAME: found = 1 - #if the .lib information is for an existing datasheet compare timing data + # if the .lib information is for an existing datasheet compare timing data for item in sheet.operating_table.rows: - #check if the new corner data is worse than the previous worse corner data + # check if the new corner data is worse than the previous worse corner data if item[0] == 'Operating Temperature': if float(TEMP) > float(item[3]): @@ -128,14 +127,13 @@ def parse_characterizer_csv(sram,f,pages): if item[0] == 'Operating Frequncy (F)': try: if float(math.floor(1000/float(MIN_PERIOD)) < float(item[3])): - item[3] = str(math.floor(1000/float(MIN_PERIOD))) + item[3] = str(math.floor( + 1000/float(MIN_PERIOD))) except Exception: pass - while(True): - if(row[col].startswith('DIN')): start = col for item in sheet.timing_table.rows: @@ -253,7 +251,6 @@ def parse_characterizer_csv(sram,f,pages): col += 1 - elif(row[col].startswith('WEb')): start = col for item in sheet.timing_table.rows: @@ -293,7 +290,6 @@ def parse_characterizer_csv(sram,f,pages): col += 1 - elif(row[col].startswith('ADDR')): start = col for item in sheet.timing_table.rows: @@ -333,198 +329,220 @@ def parse_characterizer_csv(sram,f,pages): col += 1 - - else: break - - new_sheet.corners_table.add_row([PROC,process_name(PROC),VOLT,TEMP,LIB_NAME.replace(OUT_DIR,'').replace(NAME,'')]) - new_sheet.dlv_table.add_row(['.lib','Synthesis models','{1}'.format(LIB_NAME,LIB_NAME.replace(OUT_DIR,''))]) + datasheet.new_sheet.corners_table.add_row([PROC, process_name( + PROC), VOLT, TEMP, LIB_NAME.replace(OUT_DIR, '').replace(NAME, '')]) + datasheet.new_sheet.dlv_table.add_row( + ['.lib', 'Synthesis models', '{1}'.format(LIB_NAME, LIB_NAME.replace(OUT_DIR, ''))]) if found == 0: - - #if this is the first corner for this sram, run first time configuration and set up tables - new_sheet = datasheet(NAME) + + # if this is the first corner for this sram, run first time configuration and set up tables + new_sheet = datasheet.datasheet(NAME) pages.append(new_sheet) new_sheet.git_id = ORIGIN_ID new_sheet.time = DATETIME new_sheet.DRC = DRC new_sheet.LVS = LVS - new_sheet.description = [NAME, NUM_WORDS, NUM_BANKS, NUM_RW_PORTS, NUM_W_PORTS, NUM_R_PORTS, TECH_NAME, WORD_SIZE, ORIGIN_ID, DATETIME] + new_sheet.description = [NAME, NUM_WORDS, NUM_BANKS, NUM_RW_PORTS, + NUM_W_PORTS, NUM_R_PORTS, TECH_NAME, WORD_SIZE, ORIGIN_ID, DATETIME] - new_sheet.corners_table = table_gen("corners") - new_sheet.corners_table.add_row(['Corner Name','Process','Power Supply','Temperature','Library Name Suffix']) - new_sheet.corners_table.add_row([PROC,process_name(PROC),VOLT,TEMP,LIB_NAME.replace(OUT_DIR,'').replace(NAME,'')]) - new_sheet.operating_table = table_gen("operating_table") - new_sheet.operating_table.add_row(['Parameter','Min','Typ','Max','Units']) - new_sheet.operating_table.add_row(['Power supply (VDD) range',VOLT,VOLT,VOLT,'Volts']) - new_sheet.operating_table.add_row(['Operating Temperature',TEMP,TEMP,TEMP,'Celsius']) + new_sheet.corners_table = table_gen.table_gen("corners") + new_sheet.corners_table.add_row( + ['Corner Name', 'Process', 'Power Supply', 'Temperature', 'Library Name Suffix']) + new_sheet.corners_table.add_row([PROC, process_name( + PROC), VOLT, TEMP, LIB_NAME.replace(OUT_DIR, '').replace(NAME, '')]) + new_sheet.operating_table = table_gen.table_gen("operating_table") + new_sheet.operating_table.add_row( + ['Parameter', 'Min', 'Typ', 'Max', 'Units']) + new_sheet.operating_table.add_row( + ['Power supply (VDD) range', VOLT, VOLT, VOLT, 'Volts']) + new_sheet.operating_table.add_row( + ['Operating Temperature', TEMP, TEMP, TEMP, 'Celsius']) try: - new_sheet.operating_table.add_row(['Operating Frequency (F)','','',str(math.floor(1000/float(MIN_PERIOD))),'MHz']) + new_sheet.operating_table.add_row(['Operating Frequency (F)', '', '', str( + math.floor(1000/float(MIN_PERIOD))), 'MHz']) except Exception: - new_sheet.operating_table.add_row(['Operating Frequency (F)','','',"not available in netlist only",'MHz']) #failed to provide non-zero MIN_PERIOD - new_sheet.timing_table = table_gen("timing") - new_sheet.timing_table.add_row(['Parameter','Min','Max','Units']) + # failed to provide non-zero MIN_PERIOD + new_sheet.operating_table.add_row( + ['Operating Frequency (F)', '', '', "not available in netlist only", 'MHz']) + new_sheet.timing_table = table_gen.table_gen("timing") + new_sheet.timing_table.add_row( + ['Parameter', 'Min', 'Max', 'Units']) while(True): if(row[col].startswith('DIN')): start = col - - new_sheet.timing_table.add_row(['{0} setup rising'.format(row[start]),row[col+1],row[col+2],'ns']) + + new_sheet.timing_table.add_row( + ['{0} setup rising'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - - new_sheet.timing_table.add_row(['{0} setup falling'.format(row[start]),row[col+1],row[col+2],'ns']) - - col += 2 - - new_sheet.timing_table.add_row(['{0} hold rising'.format(row[start]),row[col+1],row[col+2],'ns']) + new_sheet.timing_table.add_row( + ['{0} setup falling'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - new_sheet.timing_table.add_row(['{0} hold falling'.format(row[start]),row[col+1],row[col+2],'ns']) + new_sheet.timing_table.add_row( + ['{0} hold rising'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - col +=1 + new_sheet.timing_table.add_row( + ['{0} hold falling'.format(row[start]), row[col+1], row[col+2], 'ns']) + + col += 2 + + col += 1 elif(row[col].startswith('DOUT')): start = col - - new_sheet.timing_table.add_row(['{0} cell rise'.format(row[start]),row[col+1],row[col+2],'ns']) + + new_sheet.timing_table.add_row( + ['{0} cell rise'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - - new_sheet.timing_table.add_row(['{0} cell fall'.format(row[start]),row[col+1],row[col+2],'ns']) - - col += 2 - - new_sheet.timing_table.add_row(['{0} rise transition'.format(row[start]),row[col+1],row[col+2],'ns']) + new_sheet.timing_table.add_row( + ['{0} cell fall'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - new_sheet.timing_table.add_row(['{0} fall transition'.format(row[start]),row[col+1],row[col+2],'ns']) + new_sheet.timing_table.add_row( + ['{0} rise transition'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - col +=1 + new_sheet.timing_table.add_row( + ['{0} fall transition'.format(row[start]), row[col+1], row[col+2], 'ns']) + + col += 2 + + col += 1 elif(row[col].startswith('CSb')): start = col - - new_sheet.timing_table.add_row(['{0} setup rising'.format(row[start]),row[col+1],row[col+2],'ns']) + + new_sheet.timing_table.add_row( + ['{0} setup rising'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - - new_sheet.timing_table.add_row(['{0} setup falling'.format(row[start]),row[col+1],row[col+2],'ns']) - - col += 2 - - new_sheet.timing_table.add_row(['{0} hold rising'.format(row[start]),row[col+1],row[col+2],'ns']) + new_sheet.timing_table.add_row( + ['{0} setup falling'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - new_sheet.timing_table.add_row(['{0} hold falling'.format(row[start]),row[col+1],row[col+2],'ns']) + new_sheet.timing_table.add_row( + ['{0} hold rising'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - col +=1 + new_sheet.timing_table.add_row( + ['{0} hold falling'.format(row[start]), row[col+1], row[col+2], 'ns']) + + col += 2 + + col += 1 elif(row[col].startswith('WEb')): start = col - - new_sheet.timing_table.add_row(['{0} setup rising'.format(row[start]),row[col+1],row[col+2],'ns']) + + new_sheet.timing_table.add_row( + ['{0} setup rising'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - - new_sheet.timing_table.add_row(['{0} setup falling'.format(row[start]),row[col+1],row[col+2],'ns']) - - col += 2 - - new_sheet.timing_table.add_row(['{0} hold rising'.format(row[start]),row[col+1],row[col+2],'ns']) + new_sheet.timing_table.add_row( + ['{0} setup falling'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - new_sheet.timing_table.add_row(['{0} hold falling'.format(row[start]),row[col+1],row[col+2],'ns']) + new_sheet.timing_table.add_row( + ['{0} hold rising'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - col +=1 + new_sheet.timing_table.add_row( + ['{0} hold falling'.format(row[start]), row[col+1], row[col+2], 'ns']) + + col += 2 + + col += 1 elif(row[col].startswith('ADDR')): start = col - - new_sheet.timing_table.add_row(['{0} setup rising'.format(row[start]),row[col+1],row[col+2],'ns']) + + new_sheet.timing_table.add_row( + ['{0} setup rising'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - - new_sheet.timing_table.add_row(['{0} setup falling'.format(row[start]),row[col+1],row[col+2],'ns']) - - col += 2 - - new_sheet.timing_table.add_row(['{0} hold rising'.format(row[start]),row[col+1],row[col+2],'ns']) + new_sheet.timing_table.add_row( + ['{0} setup falling'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - new_sheet.timing_table.add_row(['{0} hold falling'.format(row[start]),row[col+1],row[col+2],'ns']) + new_sheet.timing_table.add_row( + ['{0} hold rising'.format(row[start]), row[col+1], row[col+2], 'ns']) col += 2 - col +=1 + new_sheet.timing_table.add_row( + ['{0} hold falling'.format(row[start]), row[col+1], row[col+2], 'ns']) + + col += 2 + + col += 1 else: break + new_sheet.dlv_table = table_gen.table_gen("dlv") + new_sheet.dlv_table.add_row(['Type', 'Description', 'Link']) - - new_sheet.dlv_table = table_gen("dlv") - new_sheet.dlv_table.add_row(['Type','Description','Link']) - - new_sheet.io_table = table_gen("io") + new_sheet.io_table = table_gen.table_gen("io") new_sheet.io_table.add_row(['Type', 'Value']) if not OPTS.netlist_only: - #physical layout files should not be generated in netlist only mode - new_sheet.dlv_table.add_row(['.gds','GDSII layout views','{0}.{1}'.format(OPTS.output_name,'gds')]) - new_sheet.dlv_table.add_row(['.lef','LEF files','{0}.{1}'.format(OPTS.output_name,'lef')]) - - - new_sheet.dlv_table.add_row(['.log','OpenRAM compile log','{0}.{1}'.format(OPTS.output_name,'log')]) - new_sheet.dlv_table.add_row(['.v','Verilog simulation models','{0}.{1}'.format(OPTS.output_name,'v')]) - new_sheet.dlv_table.add_row(['.html','This datasheet','{0}.{1}'.format(OPTS.output_name,'html')]) - new_sheet.dlv_table.add_row(['.lib','Synthesis models','{1}'.format(LIB_NAME,LIB_NAME.replace(OUT_DIR,''))]) - new_sheet.dlv_table.add_row(['.py','OpenRAM configuration file','{0}.{1}'.format(OPTS.output_name,'py')]) - new_sheet.dlv_table.add_row(['.sp','SPICE netlists','{0}.{1}'.format(OPTS.output_name,'sp')]) - - new_sheet.io_table.add_row(['WORD_SIZE',WORD_SIZE]) - new_sheet.io_table.add_row(['NUM_WORDS',NUM_WORDS]) - new_sheet.io_table.add_row(['NUM_BANKS',NUM_BANKS]) - new_sheet.io_table.add_row(['NUM_RW_PORTS',NUM_RW_PORTS]) - new_sheet.io_table.add_row(['NUM_R_PORTS',NUM_R_PORTS]) - new_sheet.io_table.add_row(['NUM_W_PORTS',NUM_W_PORTS]) - new_sheet.io_table.add_row(['Area',sram.width * sram.height]) - - + # physical layout files should not be generated in netlist only mode + new_sheet.dlv_table.add_row( + ['.gds', 'GDSII layout views', '{0}.{1}'.format(OPTS.output_name, 'gds')]) + new_sheet.dlv_table.add_row( + ['.lef', 'LEF files', '{0}.{1}'.format(OPTS.output_name, 'lef')]) + new_sheet.dlv_table.add_row( + ['.log', 'OpenRAM compile log', '{0}.{1}'.format(OPTS.output_name, 'log')]) + new_sheet.dlv_table.add_row( + ['.v', 'Verilog simulation models', '{0}.{1}'.format(OPTS.output_name, 'v')]) + new_sheet.dlv_table.add_row( + ['.html', 'This datasheet', '{0}.{1}'.format(OPTS.output_name, 'html')]) + new_sheet.dlv_table.add_row( + ['.lib', 'Synthesis models', '{1}'.format(LIB_NAME, LIB_NAME.replace(OUT_DIR, ''))]) + new_sheet.dlv_table.add_row( + ['.py', 'OpenRAM configuration file', '{0}.{1}'.format(OPTS.output_name, 'py')]) + new_sheet.dlv_table.add_row( + ['.sp', 'SPICE netlists', '{0}.{1}'.format(OPTS.output_name, 'sp')]) + new_sheet.io_table.add_row(['WORD_SIZE', WORD_SIZE]) + new_sheet.io_table.add_row(['NUM_WORDS', NUM_WORDS]) + new_sheet.io_table.add_row(['NUM_BANKS', NUM_BANKS]) + new_sheet.io_table.add_row(['NUM_RW_PORTS', NUM_RW_PORTS]) + new_sheet.io_table.add_row(['NUM_R_PORTS', NUM_R_PORTS]) + new_sheet.io_table.add_row(['NUM_W_PORTS', NUM_W_PORTS]) + new_sheet.io_table.add_row(['Area', sram.width * sram.height]) class datasheet_gen(): - def datasheet_write(sram,name): - + def datasheet_write(sram, name): in_dir = OPTS.openram_temp if not (os.path.isdir(in_dir)): os.mkdir(in_dir) - datasheets = [] parse_characterizer_csv(sram, in_dir + "/datasheet.info", datasheets) - for sheets in datasheets: with open(name, 'w+') as f: sheets.generate_html() diff --git a/compiler/datasheet/library_page/lib_table_gen.py b/compiler/datasheet/library_page/lib_table_gen.py new file mode 100644 index 00000000..c35d09c0 --- /dev/null +++ b/compiler/datasheet/library_page/lib_table_gen.py @@ -0,0 +1,43 @@ +class table_gen: + def __init__(self, name): + self.name = name + self.rows = [] + self.table_id = 'data' + + def add_row(self, row): + self.rows.append(row) + + def gen_table_head(self): + html = '' + + html += '' + html += '' + for col in self.rows[0]: + html += '' + str(col) + '' + html += '' + html += '' + return html + + def gen_table_body(self): + html = '' + + html += '' + html += '' + for row in self.rows[1:]: + html += '' + for col in row: + html += '' + str(col) + '' + html += '' + html += '' + html += '' + return html + + def to_html(self): + + html = '' + html += '' + html += self.gen_table_head() + html += self.gen_table_body() + html += '
' + + return html diff --git a/compiler/datasheet/library_page/library.py b/compiler/datasheet/library_page/library.py new file mode 100644 index 00000000..d23d4a75 --- /dev/null +++ b/compiler/datasheet/library_page/library.py @@ -0,0 +1,16 @@ +import os +import base64 + + +class library(): + + def __init__(self): + self.html = '' + + def generate_html(self): + vlsi_logo = 0 + with open(os.path.abspath(os.environ.get("OPENRAM_HOME")) + '/datasheet/assets/vlsi_logo.png', "rb") as image_file: + vlsi_logo = base64.b64encode(image_file.read()) + + self.html += 'VLSIDA'.format(str(vlsi_logo)[ + 2:-1]) diff --git a/compiler/datasheet/library_page/library_gen.py b/compiler/datasheet/library_page/library_gen.py new file mode 100644 index 00000000..ca7f631d --- /dev/null +++ b/compiler/datasheet/library_page/library_gen.py @@ -0,0 +1,60 @@ +import library +import csv + + +class library_item(): + def __init__(self): + self.comment = '' + self.word_size = '' + self.num_words = '' + self.num_banks = '' + self.num_rw_ports = '' + self.num_r_ports = '' + self.num_w_ports = '' + self.Area = '' + self.git_id = '' + self.technology = '' + self.min_op = '' + + +class library_gen(): + def library_write(name): + with open(name, 'w+') as f: + library_page.generate_html() + f.write(library_page.html) + + def search_file(file, name): + length = len(name) + part = file.read(length) + i = 0 + while True: + if part == name: + break + char = file.read(1) + if not char: + return + part = part[1:] + char + i += 1 + return i + + def parse_html(file): + item = library_item() + start_tag = '' + + with open(file, 'r') as f: + start_byte = library_gen.search_file(f, start_tag) + len(start_tag) + end_byte = library_gen.search_file(f, end_tag) + start_byte + + f.seek(start_byte) + item.comment = f.read(end_byte - start_byte) + print(item.comment) + return item + + def parse_comment(comment, item): + + pass + + +library_page = library.library() +library_gen.parse_html('../../temp/sram_2_16_scn4m_subm.html') From 813a551691fd6e98f09e3f38184ca7b0c528b2e4 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Tue, 15 Jan 2019 20:48:20 -0800 Subject: [PATCH 04/44] comment parsing 1/2 complete; page gen setup complete --- compiler/datasheet/datasheet.py | 12 ++- compiler/datasheet/library_page/library.py | 2 +- .../datasheet/library_page/library_gen.py | 87 ++++++++++++++++--- 3 files changed, 83 insertions(+), 18 deletions(-) diff --git a/compiler/datasheet/datasheet.py b/compiler/datasheet/datasheet.py index 566dfc80..22a50cb9 100644 --- a/compiler/datasheet/datasheet.py +++ b/compiler/datasheet/datasheet.py @@ -1,6 +1,5 @@ from table_gen import * import os -import csv import base64 from globals import OPTS @@ -22,13 +21,12 @@ class datasheet(): # css styling is kept in a seperate file self.html += datasheet_css.read() - -# with open(OPTS.openram_temp + "/datasheet.info") as info: + with open(OPTS.openram_temp + "/datasheet.info") as info: self.html += '' diff --git a/compiler/datasheet/library_page/library.py b/compiler/datasheet/library_page/library.py index d23d4a75..3477164c 100644 --- a/compiler/datasheet/library_page/library.py +++ b/compiler/datasheet/library_page/library.py @@ -7,7 +7,7 @@ class library(): def __init__(self): self.html = '' - def generate_html(self): + def generate_html(self,book): vlsi_logo = 0 with open(os.path.abspath(os.environ.get("OPENRAM_HOME")) + '/datasheet/assets/vlsi_logo.png', "rb") as image_file: vlsi_logo = base64.b64encode(image_file.read()) diff --git a/compiler/datasheet/library_page/library_gen.py b/compiler/datasheet/library_page/library_gen.py index ca7f631d..ca5942f7 100644 --- a/compiler/datasheet/library_page/library_gen.py +++ b/compiler/datasheet/library_page/library_gen.py @@ -1,9 +1,10 @@ import library -import csv +from pathlib import Path class library_item(): def __init__(self): + self.name = '' self.comment = '' self.word_size = '' self.num_words = '' @@ -13,14 +14,15 @@ class library_item(): self.num_w_ports = '' self.Area = '' self.git_id = '' - self.technology = '' - self.min_op = '' + self.tech_name = '' + self.min_period = '' + self.datetime = '' class library_gen(): - def library_write(name): + def library_write(name, book): with open(name, 'w+') as f: - library_page.generate_html() + library_page.generate_html(book) f.write(library_page.html) def search_file(file, name): @@ -37,6 +39,66 @@ class library_gen(): i += 1 return i + def parse_comment(item): + row = item.comment.split(',') + print(row) + found = 0 + col = 0 + + item.name = row[col] + col += 1 + + item.num_words = row[col] + col += 1 + + item.num_banks = row[col] + col += 1 + + item.num_rw_ports = row[col] + col += 1 + + item.num_w_port = row[col] + col += 1 + + item.num_r_ports = row[col] + col += 1 + + item.tech_name = row[col] + col += 1 + print(item.tech_name) +# TEMP = row[col] + col += 1 + +# VOLT = row[col] + col += 1 + +# PROC = row[col] + col += 1 + + item.min_period = row[col] + col += 1 + print(item.min_period) +# OUT_DIR = row[col] + col += 1 + +# LIB_NAME = row[col] + col += 1 + + item.word_size = row[col] + col += 1 + + item.git_id = row[col] + col += 1 + + item.datetime = row[col] + col += 1 + +# DRC = row[col] + col += 1 + +# LVS = row[col] + col += 1 + def parse_html(file): item = library_item() start_tag = '' - - with open(file, 'r') as f: - start_byte = library_gen.search_file(f, start_tag) + len(start_tag) - end_byte = library_gen.search_file(f, end_tag) + start_byte - - f.seek(start_byte) - item.comment = f.read(end_byte - start_byte) - library_gen.parse_comment(item) - - return item - - def get_file_tree(path): - return list(Path(path).rglob("*.html")) - - -datasheet_list = library_gen.get_file_tree('./deliverables') -print(datasheet_list) -library_page = library.library() -book = [] -for datasheet in datasheet_list: - book.append(library_gen.parse_html(datasheet)) -library_gen.library_write('index.html', book) From 2e7d2483ebab5a72f728dd66b2fa8872562e5072 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 16 Jan 2019 09:42:01 -0800 Subject: [PATCH 06/44] Use github formatted 3-clause BSD license --- LICENSE | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/LICENSE b/LICENSE index 9a86ca1f..7d362d0c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,31 +1,31 @@ +BSD 3-Clause License + Copyright 2018 Regents of the University of California and The Board of Regents for the Oklahoma Agricultural and Mechanical College (acting for and on behalf of Oklahoma State University) +All rights reserved. Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: +modification, are permitted provided that the following conditions are met: -1. Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. -3. Neither the name of the copyright holder nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - From 9431b93a1d411c14b9edf69d1712f3c5eed69c2b Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 16 Jan 2019 09:43:31 -0800 Subject: [PATCH 07/44] Update copyright year --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 7d362d0c..761f6e8b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ BSD 3-Clause License -Copyright 2018 Regents of the University of California and The Board +Copyright (c) 2019 Regents of the University of California and The Board of Regents for the Oklahoma Agricultural and Mechanical College (acting for and on behalf of Oklahoma State University) All rights reserved. From 553894c5a2da7e8485e4708be712e37bb3dc6748 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 16 Jan 2019 10:07:10 -0800 Subject: [PATCH 08/44] Remove library code and move to its own repository --- lib/Makefile | 14 -------- lib/README.md | 5 --- lib/freepdk45/Makefile | 32 ------------------ .../configs/sram_128b_1024_1rw_freepdk45.py | 8 ----- .../configs/sram_32b_1024_1rw_freepdk45.py | 7 ---- .../configs/sram_32b_2048_1rw_freepdk45.py | 7 ---- .../configs/sram_32b_256_1rw_freepdk45.py | 7 ---- .../configs/sram_32b_512_1rw_freepdk45.py | 7 ---- .../configs/sram_64b_1024_1rw_freepdk45.py | 7 ---- .../configs/sram_8b_1024_1rw_freepdk45.py | 7 ---- .../configs/sram_8b_256_1rw_freepdk45.py | 7 ---- .../configs/sram_8b_512_1rw_freepdk45.py | 7 ---- lib/scn4m_subm/Makefile | 33 ------------------- .../configs/sram_128b_1024_1rw_scn4m_subm.py | 12 ------- .../configs/sram_32b_1024_1rw_scn4m_subm.py | 12 ------- .../configs/sram_32b_2048_1rw_scn4m_subm.py | 12 ------- .../configs/sram_32b_256_1rw_scn4m_subm.py | 12 ------- .../configs/sram_32b_512_1rw_scn4m_subm.py | 12 ------- .../configs/sram_64b_1024_1rw_scn4m_subm.py | 12 ------- .../configs/sram_8b_1024_1rw_scn4m_subm.py | 12 ------- .../configs/sram_8b_256_1rw_scn4m_subm.py | 12 ------- .../configs/sram_8b_512_1rw_scn4m_subm.py | 12 ------- 22 files changed, 256 deletions(-) delete mode 100644 lib/Makefile delete mode 100644 lib/README.md delete mode 100644 lib/freepdk45/Makefile delete mode 100644 lib/freepdk45/configs/sram_128b_1024_1rw_freepdk45.py delete mode 100644 lib/freepdk45/configs/sram_32b_1024_1rw_freepdk45.py delete mode 100644 lib/freepdk45/configs/sram_32b_2048_1rw_freepdk45.py delete mode 100644 lib/freepdk45/configs/sram_32b_256_1rw_freepdk45.py delete mode 100644 lib/freepdk45/configs/sram_32b_512_1rw_freepdk45.py delete mode 100644 lib/freepdk45/configs/sram_64b_1024_1rw_freepdk45.py delete mode 100644 lib/freepdk45/configs/sram_8b_1024_1rw_freepdk45.py delete mode 100644 lib/freepdk45/configs/sram_8b_256_1rw_freepdk45.py delete mode 100644 lib/freepdk45/configs/sram_8b_512_1rw_freepdk45.py delete mode 100644 lib/scn4m_subm/Makefile delete mode 100644 lib/scn4m_subm/configs/sram_128b_1024_1rw_scn4m_subm.py delete mode 100644 lib/scn4m_subm/configs/sram_32b_1024_1rw_scn4m_subm.py delete mode 100644 lib/scn4m_subm/configs/sram_32b_2048_1rw_scn4m_subm.py delete mode 100644 lib/scn4m_subm/configs/sram_32b_256_1rw_scn4m_subm.py delete mode 100644 lib/scn4m_subm/configs/sram_32b_512_1rw_scn4m_subm.py delete mode 100644 lib/scn4m_subm/configs/sram_64b_1024_1rw_scn4m_subm.py delete mode 100644 lib/scn4m_subm/configs/sram_8b_1024_1rw_scn4m_subm.py delete mode 100644 lib/scn4m_subm/configs/sram_8b_256_1rw_scn4m_subm.py delete mode 100644 lib/scn4m_subm/configs/sram_8b_512_1rw_scn4m_subm.py diff --git a/lib/Makefile b/lib/Makefile deleted file mode 100644 index d9debb2c..00000000 --- a/lib/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -SUBDIRS := $(wildcard */.) -SUBDIRSCLEAN=$(addsuffix clean,$(SUBDIRS)) - -all: $(SUBDIRS) - -$(SUBDIRS): - $(MAKE) -k -C $@ - -clean: - for dir in $(SUBDIRS); do \ - $(MAKE) -C $$dir $@; \ - done - -.PHONY: all $(SUBDIRS) $(SUBDIRSCLEAN) diff --git a/lib/README.md b/lib/README.md deleted file mode 100644 index b284ec12..00000000 --- a/lib/README.md +++ /dev/null @@ -1,5 +0,0 @@ -This directory contains a set of common sizes based on -discussions with users. All of the files are pre-computed -to that common-case users don't need to setup/use OpenRAM. -The results will be updated automatically as improvements -are made to OpenRAM. \ No newline at end of file diff --git a/lib/freepdk45/Makefile b/lib/freepdk45/Makefile deleted file mode 100644 index cf883d4c..00000000 --- a/lib/freepdk45/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -CUR_DIR = $(shell pwd) -TEST_DIR = ${CUR_DIR}/tests - -#MAKEFLAGS += -j 2 - -CONFIG_DIR = configs -OUT_DIRS = sp lib lef gds verilog -$(shell mkdir -p $(OUT_DIRS)) - -SRCS=$(wildcard $(CONFIG_DIR)/*.py) -SPICES=$(SRCS:.py=.sp) -all : $(SPICES) - -# Characterize and perform DRC/LVS -OPTS = -c -# Do not characterize or perform DRC/LVS -#OPTS += -n -# Verbosity -OPTS += -v -%.sp : %.py - $(eval bname=$(basename $(notdir $<))) - openram.py $(OPTS) $< 2>&1 > $(bname).log - mv $(bname).lef lef - mv $(bname).v verilog - mv $(bname).sp sp - mv $(bname).gds gds - mv $(bname)*.lib lib - -clean: - rm -f *.log configs/*.pyc *~ *.gds *.lib *.sp *.v *.lef - rm -f gds/* lef/* lib/* sp/* verilog/* - diff --git a/lib/freepdk45/configs/sram_128b_1024_1rw_freepdk45.py b/lib/freepdk45/configs/sram_128b_1024_1rw_freepdk45.py deleted file mode 100644 index 1d131e16..00000000 --- a/lib/freepdk45/configs/sram_128b_1024_1rw_freepdk45.py +++ /dev/null @@ -1,8 +0,0 @@ -word_size = 128 -num_words = 1024 -num_banks = 1 - -tech_name = "freepdk45" -process_corners = ["TT"] -supply_voltages = [1.0] -temperatures = [25] diff --git a/lib/freepdk45/configs/sram_32b_1024_1rw_freepdk45.py b/lib/freepdk45/configs/sram_32b_1024_1rw_freepdk45.py deleted file mode 100644 index 1085a755..00000000 --- a/lib/freepdk45/configs/sram_32b_1024_1rw_freepdk45.py +++ /dev/null @@ -1,7 +0,0 @@ -word_size = 32 -num_words = 1024 - -tech_name = "freepdk45" -process_corners = ["TT"] -supply_voltages = [1.0] -temperatures = [25] diff --git a/lib/freepdk45/configs/sram_32b_2048_1rw_freepdk45.py b/lib/freepdk45/configs/sram_32b_2048_1rw_freepdk45.py deleted file mode 100644 index e96bac37..00000000 --- a/lib/freepdk45/configs/sram_32b_2048_1rw_freepdk45.py +++ /dev/null @@ -1,7 +0,0 @@ -word_size = 32 -num_words = 2048 - -tech_name = "freepdk45" -process_corners = ["TT"] -supply_voltages = [1.0] -temperatures = [25] diff --git a/lib/freepdk45/configs/sram_32b_256_1rw_freepdk45.py b/lib/freepdk45/configs/sram_32b_256_1rw_freepdk45.py deleted file mode 100644 index 7ca6be89..00000000 --- a/lib/freepdk45/configs/sram_32b_256_1rw_freepdk45.py +++ /dev/null @@ -1,7 +0,0 @@ -word_size = 32 -num_words = 256 - -tech_name = "freepdk45" -process_corners = ["TT"] -supply_voltages = [1.0] -temperatures = [25] diff --git a/lib/freepdk45/configs/sram_32b_512_1rw_freepdk45.py b/lib/freepdk45/configs/sram_32b_512_1rw_freepdk45.py deleted file mode 100644 index 960e9f73..00000000 --- a/lib/freepdk45/configs/sram_32b_512_1rw_freepdk45.py +++ /dev/null @@ -1,7 +0,0 @@ -word_size = 32 -num_words = 512 - -tech_name = "freepdk45" -process_corners = ["TT"] -supply_voltages = [1.0] -temperatures = [25] diff --git a/lib/freepdk45/configs/sram_64b_1024_1rw_freepdk45.py b/lib/freepdk45/configs/sram_64b_1024_1rw_freepdk45.py deleted file mode 100644 index bb421711..00000000 --- a/lib/freepdk45/configs/sram_64b_1024_1rw_freepdk45.py +++ /dev/null @@ -1,7 +0,0 @@ -word_size = 64 -num_words = 1024 - -tech_name = "freepdk45" -process_corners = ["TT"] -supply_voltages = [1.0] -temperatures = [25] diff --git a/lib/freepdk45/configs/sram_8b_1024_1rw_freepdk45.py b/lib/freepdk45/configs/sram_8b_1024_1rw_freepdk45.py deleted file mode 100644 index 838d49d7..00000000 --- a/lib/freepdk45/configs/sram_8b_1024_1rw_freepdk45.py +++ /dev/null @@ -1,7 +0,0 @@ -word_size = 8 -num_words = 1024 - -tech_name = "freepdk45" -process_corners = ["TT"] -supply_voltages = [1.0] -temperatures = [25] diff --git a/lib/freepdk45/configs/sram_8b_256_1rw_freepdk45.py b/lib/freepdk45/configs/sram_8b_256_1rw_freepdk45.py deleted file mode 100644 index 84daa8f0..00000000 --- a/lib/freepdk45/configs/sram_8b_256_1rw_freepdk45.py +++ /dev/null @@ -1,7 +0,0 @@ -word_size = 8 -num_words = 256 - -tech_name = "freepdk45" -process_corners = ["TT"] -supply_voltages = [1.0] -temperatures = [25] diff --git a/lib/freepdk45/configs/sram_8b_512_1rw_freepdk45.py b/lib/freepdk45/configs/sram_8b_512_1rw_freepdk45.py deleted file mode 100644 index ab85aaa4..00000000 --- a/lib/freepdk45/configs/sram_8b_512_1rw_freepdk45.py +++ /dev/null @@ -1,7 +0,0 @@ -word_size = 8 -num_words = 512 - -tech_name = "freepdk45" -process_corners = ["TT"] -supply_voltages = [1.0] -temperatures = [25] diff --git a/lib/scn4m_subm/Makefile b/lib/scn4m_subm/Makefile deleted file mode 100644 index f833836a..00000000 --- a/lib/scn4m_subm/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -CUR_DIR = $(shell pwd) -TEST_DIR = ${CUR_DIR}/tests - -#MAKEFLAGS += -j 2 - -CONFIG_DIR = configs -OUT_DIRS = sp lib lef gds verilog -$(shell mkdir -p $(OUT_DIRS)) - -SRCS=$(wildcard $(CONFIG_DIR)/*.py) -SPICES=$(SRCS:.py=.sp) -all : $(SPICES) - -OPTS = -# Characterize and perform DRC/LVS -#OPTS = -c -# Do not characterize or perform DRC/LVS -#OPTS += -n -# Verbosity -OPTS += -v -%.sp : %.py - $(eval bname=$(basename $(notdir $<))) - openram.py $(OPTS) $< 2>&1 > $(bname).log - mv $(bname).lef lef - mv $(bname).v verilog - mv $(bname).sp sp - mv $(bname).gds gds - mv $(bname)*.lib lib - -clean: - rm -f *.log configs/*.pyc *~ *.gds *.lib *.sp *.v *.lef - rm -f gds/* lef/* lib/* sp/* verilog/* - diff --git a/lib/scn4m_subm/configs/sram_128b_1024_1rw_scn4m_subm.py b/lib/scn4m_subm/configs/sram_128b_1024_1rw_scn4m_subm.py deleted file mode 100644 index aad83344..00000000 --- a/lib/scn4m_subm/configs/sram_128b_1024_1rw_scn4m_subm.py +++ /dev/null @@ -1,12 +0,0 @@ -word_size = 128 -num_words = 1024 - -tech_name = "scn4m_subm" -process_corners = ["TT"] -supply_voltages = [ 5.0 ] -temperatures = [ 25 ] - -drc_name = "magic" -lvs_name = "netgen" -pex_name = "magic" - diff --git a/lib/scn4m_subm/configs/sram_32b_1024_1rw_scn4m_subm.py b/lib/scn4m_subm/configs/sram_32b_1024_1rw_scn4m_subm.py deleted file mode 100644 index 162eaa6e..00000000 --- a/lib/scn4m_subm/configs/sram_32b_1024_1rw_scn4m_subm.py +++ /dev/null @@ -1,12 +0,0 @@ -word_size = 32 -num_words = 1024 - -tech_name = "scn4m_subm" -process_corners = ["TT"] -supply_voltages = [ 5.0 ] -temperatures = [ 25 ] - -drc_name = "magic" -lvs_name = "netgen" -pex_name = "magic" - diff --git a/lib/scn4m_subm/configs/sram_32b_2048_1rw_scn4m_subm.py b/lib/scn4m_subm/configs/sram_32b_2048_1rw_scn4m_subm.py deleted file mode 100644 index 7ce98b2e..00000000 --- a/lib/scn4m_subm/configs/sram_32b_2048_1rw_scn4m_subm.py +++ /dev/null @@ -1,12 +0,0 @@ -word_size = 32 -num_words = 2048 - -tech_name = "scn4m_subm" -process_corners = ["TT"] -supply_voltages = [ 5.0 ] -temperatures = [ 25 ] - -drc_name = "magic" -lvs_name = "netgen" -pex_name = "magic" - diff --git a/lib/scn4m_subm/configs/sram_32b_256_1rw_scn4m_subm.py b/lib/scn4m_subm/configs/sram_32b_256_1rw_scn4m_subm.py deleted file mode 100644 index 33547f16..00000000 --- a/lib/scn4m_subm/configs/sram_32b_256_1rw_scn4m_subm.py +++ /dev/null @@ -1,12 +0,0 @@ -word_size = 32 -num_words = 256 - -tech_name = "scn4m_subm" -process_corners = ["TT"] -supply_voltages = [ 5.0 ] -temperatures = [ 25 ] - -drc_name = "magic" -lvs_name = "netgen" -pex_name = "magic" - diff --git a/lib/scn4m_subm/configs/sram_32b_512_1rw_scn4m_subm.py b/lib/scn4m_subm/configs/sram_32b_512_1rw_scn4m_subm.py deleted file mode 100644 index 88d5fc96..00000000 --- a/lib/scn4m_subm/configs/sram_32b_512_1rw_scn4m_subm.py +++ /dev/null @@ -1,12 +0,0 @@ -word_size = 32 -num_words = 512 - -tech_name = "scn4m_subm" -process_corners = ["TT"] -supply_voltages = [ 5.0 ] -temperatures = [ 25 ] - -drc_name = "magic" -lvs_name = "netgen" -pex_name = "magic" - diff --git a/lib/scn4m_subm/configs/sram_64b_1024_1rw_scn4m_subm.py b/lib/scn4m_subm/configs/sram_64b_1024_1rw_scn4m_subm.py deleted file mode 100644 index c9d7d116..00000000 --- a/lib/scn4m_subm/configs/sram_64b_1024_1rw_scn4m_subm.py +++ /dev/null @@ -1,12 +0,0 @@ -word_size = 64 -num_words = 1024 - -tech_name = "scn4m_subm" -process_corners = ["TT"] -supply_voltages = [ 5.0 ] -temperatures = [ 25 ] - -drc_name = "magic" -lvs_name = "netgen" -pex_name = "magic" - diff --git a/lib/scn4m_subm/configs/sram_8b_1024_1rw_scn4m_subm.py b/lib/scn4m_subm/configs/sram_8b_1024_1rw_scn4m_subm.py deleted file mode 100644 index 3770c138..00000000 --- a/lib/scn4m_subm/configs/sram_8b_1024_1rw_scn4m_subm.py +++ /dev/null @@ -1,12 +0,0 @@ -word_size = 8 -num_words = 1024 - -tech_name = "scn4m_subm" -process_corners = ["TT"] -supply_voltages = [ 5.0 ] -temperatures = [ 25 ] - -drc_name = "magic" -lvs_name = "netgen" -pex_name = "magic" - diff --git a/lib/scn4m_subm/configs/sram_8b_256_1rw_scn4m_subm.py b/lib/scn4m_subm/configs/sram_8b_256_1rw_scn4m_subm.py deleted file mode 100644 index 37e4bf50..00000000 --- a/lib/scn4m_subm/configs/sram_8b_256_1rw_scn4m_subm.py +++ /dev/null @@ -1,12 +0,0 @@ -word_size = 8 -num_words = 256 - -tech_name = "scn4m_subm" -process_corners = ["TT"] -supply_voltages = [ 5.0 ] -temperatures = [ 25 ] - -drc_name = "magic" -lvs_name = "netgen" -pex_name = "magic" - diff --git a/lib/scn4m_subm/configs/sram_8b_512_1rw_scn4m_subm.py b/lib/scn4m_subm/configs/sram_8b_512_1rw_scn4m_subm.py deleted file mode 100644 index 5f4676d7..00000000 --- a/lib/scn4m_subm/configs/sram_8b_512_1rw_scn4m_subm.py +++ /dev/null @@ -1,12 +0,0 @@ -word_size = 8 -num_words = 512 - -tech_name = "scn4m_subm" -process_corners = ["TT"] -supply_voltages = [ 5.0 ] -temperatures = [ 25 ] - -drc_name = "magic" -lvs_name = "netgen" -pex_name = "magic" - From 0556b864245e15d799bf7d7227138d1db2c34381 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Wed, 16 Jan 2019 14:52:01 -0800 Subject: [PATCH 09/44] html datasheet no longer dependeds on sram --- compiler/characterizer/lib.py | 4 ++-- compiler/datasheet/datasheet_gen.py | 12 +++++++----- compiler/sram.py | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/compiler/characterizer/lib.py b/compiler/characterizer/lib.py index 7b10eb8f..156481ce 100644 --- a/compiler/characterizer/lib.py +++ b/compiler/characterizer/lib.py @@ -530,7 +530,7 @@ class lib: "sram_{0}_{1}_{2}".format(OPTS.word_size, OPTS.num_words, OPTS.tech_name), OPTS.num_words, OPTS.num_banks, - OPTS.num_rw_ports, + OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports, OPTS.tech_name, @@ -555,7 +555,7 @@ class lib: LVS = str(total_lvs_errors) datasheet.write("{0},{1},".format(DRC, LVS)) - + datasheet.write(str(self.sram.width * self.sram.height)+',') for port in self.all_ports: #DIN timings if port in self.write_ports: diff --git a/compiler/datasheet/datasheet_gen.py b/compiler/datasheet/datasheet_gen.py index 93ab783c..902c058c 100644 --- a/compiler/datasheet/datasheet_gen.py +++ b/compiler/datasheet/datasheet_gen.py @@ -4,7 +4,7 @@ This is a script to load data from the characterization and layout processes int a web friendly html datasheet. """ # TODO: -# include log file +# include power # Diagram generation # Improve css @@ -31,7 +31,7 @@ def process_name(corner): return "custom" -def parse_characterizer_csv(sram, f, pages): +def parse_characterizer_csv(f, pages): """ Parses output data of the Liberty file generator in order to construct the timing and current table @@ -98,6 +98,8 @@ def parse_characterizer_csv(sram, f, pages): LVS = row[col] col += 1 + AREA = row[col] + col += 1 for sheet in pages: if sheet.name == NAME: @@ -529,11 +531,11 @@ def parse_characterizer_csv(sram, f, pages): new_sheet.io_table.add_row(['NUM_RW_PORTS', NUM_RW_PORTS]) new_sheet.io_table.add_row(['NUM_R_PORTS', NUM_R_PORTS]) new_sheet.io_table.add_row(['NUM_W_PORTS', NUM_W_PORTS]) - new_sheet.io_table.add_row(['Area', sram.width * sram.height]) + new_sheet.io_table.add_row(['Area', AREA]) class datasheet_gen(): - def datasheet_write(sram, name): + def datasheet_write(name): in_dir = OPTS.openram_temp @@ -541,7 +543,7 @@ class datasheet_gen(): os.mkdir(in_dir) datasheets = [] - parse_characterizer_csv(sram, in_dir + "/datasheet.info", datasheets) + parse_characterizer_csv(in_dir + "/datasheet.info", datasheets) for sheets in datasheets: with open(name, 'w+') as f: diff --git a/compiler/sram.py b/compiler/sram.py index a929434e..5ff28d47 100644 --- a/compiler/sram.py +++ b/compiler/sram.py @@ -122,7 +122,7 @@ class sram(): from datasheet_gen import datasheet_gen dname = OPTS.output_path + self.s.name + ".html" debug.print_raw("Datasheet: Writing to {0}".format(dname)) - datasheet_gen.datasheet_write(self.s,dname) + datasheet_gen.datasheet_write(dname) print_time("Datasheet", datetime.datetime.now(), start_time) # Write a verilog model From 41b8e8665b168ec93b3b2f746cb8806834745ea5 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Wed, 16 Jan 2019 15:43:08 -0800 Subject: [PATCH 10/44] updated datasheet descriptors --- compiler/datasheet/datasheet_gen.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/compiler/datasheet/datasheet_gen.py b/compiler/datasheet/datasheet_gen.py index 902c058c..6786c7bf 100644 --- a/compiler/datasheet/datasheet_gen.py +++ b/compiler/datasheet/datasheet_gen.py @@ -135,7 +135,7 @@ def parse_characterizer_csv(f, pages): pass while(True): - + col_start = col if(row[col].startswith('DIN')): start = col for item in sheet.timing_table.rows: @@ -332,11 +332,13 @@ def parse_characterizer_csv(f, pages): col += 1 else: + for element in row[col_start: col - 1]: + sheet.description.append(str(element)) break - datasheet.new_sheet.corners_table.add_row([PROC, process_name( + new_sheet.corners_table.add_row([PROC, process_name( PROC), VOLT, TEMP, LIB_NAME.replace(OUT_DIR, '').replace(NAME, '')]) - datasheet.new_sheet.dlv_table.add_row( + new_sheet.dlv_table.add_row( ['.lib', 'Synthesis models', '{1}'.format(LIB_NAME, LIB_NAME.replace(OUT_DIR, ''))]) if found == 0: @@ -349,15 +351,16 @@ def parse_characterizer_csv(f, pages): new_sheet.time = DATETIME new_sheet.DRC = DRC new_sheet.LVS = LVS - new_sheet.description = [NAME, NUM_WORDS, NUM_BANKS, NUM_RW_PORTS, - NUM_W_PORTS, NUM_R_PORTS, TECH_NAME, WORD_SIZE, ORIGIN_ID, DATETIME] + new_sheet.description = [NAME, NUM_WORDS, NUM_BANKS, NUM_RW_PORTS, NUM_W_PORTS, + NUM_R_PORTS, TECH_NAME, MIN_PERIOD, WORD_SIZE, ORIGIN_ID, DATETIME] new_sheet.corners_table = table_gen.table_gen("corners") new_sheet.corners_table.add_row( ['Corner Name', 'Process', 'Power Supply', 'Temperature', 'Library Name Suffix']) new_sheet.corners_table.add_row([PROC, process_name( PROC), VOLT, TEMP, LIB_NAME.replace(OUT_DIR, '').replace(NAME, '')]) - new_sheet.operating_table = table_gen.table_gen("operating_table") + new_sheet.operating_table = table_gen.table_gen( + "operating_table") new_sheet.operating_table.add_row( ['Parameter', 'Min', 'Typ', 'Max', 'Units']) new_sheet.operating_table.add_row( @@ -376,6 +379,7 @@ def parse_characterizer_csv(f, pages): new_sheet.timing_table.add_row( ['Parameter', 'Min', 'Max', 'Units']) while(True): + col_start = col if(row[col].startswith('DIN')): start = col @@ -497,6 +501,8 @@ def parse_characterizer_csv(f, pages): col += 1 else: + for element in row[col_start:col-1]: + sheet.description.append(str(element)) break new_sheet.dlv_table = table_gen.table_gen("dlv") From 25b0da404f6408ec435c9bdd86a348c2f04793bd Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Wed, 16 Jan 2019 16:08:41 -0800 Subject: [PATCH 11/44] removed EOL error in comment --- compiler/datasheet/datasheet.py | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/datasheet/datasheet.py b/compiler/datasheet/datasheet.py index 22a50cb9..d15733d5 100644 --- a/compiler/datasheet/datasheet.py +++ b/compiler/datasheet/datasheet.py @@ -27,7 +27,6 @@ class datasheet(): self.html += row # for item in self.description: # self.html += item + ',' - self.html += 'EOL' self.html += '-->' vlsi_logo = 0 From a418431a42d9ee25ce7b93449f49ec2debbf222e Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 16 Jan 2019 16:15:38 -0800 Subject: [PATCH 12/44] First draft of sram_factory code --- compiler/base/design.py | 1 - compiler/base/hierarchy_design.py | 12 +--- compiler/base/hierarchy_spice.py | 15 ++-- compiler/bitcells/bitcell.py | 5 +- compiler/bitcells/bitcell_1rw_1r.py | 5 +- compiler/bitcells/pbitcell.py | 8 +-- compiler/bitcells/replica_bitcell.py | 5 +- compiler/bitcells/replica_bitcell_1rw_1r.py | 5 +- compiler/bitcells/replica_pbitcell.py | 11 ++- compiler/globals.py | 3 + compiler/modules/bank.py | 72 +++++++++---------- compiler/modules/bank_select.py | 24 +++---- compiler/modules/bitcell_array.py | 19 ++--- compiler/modules/control_logic.py | 62 ++++++++-------- compiler/modules/delay_chain.py | 12 ++-- compiler/modules/dff_array.py | 10 ++- compiler/modules/dff_buf.py | 17 ++--- compiler/modules/dff_buf_array.py | 8 ++- compiler/modules/dff_inv.py | 11 ++- compiler/modules/dff_inv_array.py | 4 +- compiler/modules/hierarchical_decoder.py | 30 ++++---- compiler/modules/hierarchical_predecode.py | 20 +++--- compiler/modules/hierarchical_predecode2x4.py | 4 +- compiler/modules/hierarchical_predecode3x8.py | 4 +- compiler/modules/multibank.py | 21 +----- compiler/modules/precharge_array.py | 20 +++--- compiler/modules/replica_bitline.py | 33 ++++----- compiler/modules/sense_amp_array.py | 17 ++--- .../modules/single_level_column_mux_array.py | 12 ++-- compiler/modules/tri_gate_array.py | 6 +- compiler/modules/wordline_driver.py | 16 ++--- compiler/modules/write_driver_array.py | 14 ++-- compiler/options.py | 28 ++++---- compiler/pgates/pand2.py | 20 ++---- compiler/pgates/pbuf.py | 22 ++---- compiler/pgates/pdriver.py | 16 ++--- compiler/pgates/pgate.py | 6 +- compiler/pgates/pinv.py | 6 +- compiler/pgates/pinvbuf.py | 21 +++--- compiler/pgates/pnand2.py | 9 +-- compiler/pgates/pnand3.py | 9 +-- compiler/pgates/pnor2.py | 7 +- compiler/pgates/precharge.py | 13 +--- compiler/pgates/ptx.py | 4 +- compiler/pgates/single_level_column_mux.py | 16 ++--- compiler/sram_base.py | 6 +- compiler/sram_config.py | 6 +- compiler/tests/04_pand2_test.py | 2 +- compiler/tests/04_pbitcell_test.py | 34 +++++---- compiler/tests/04_pbuf_test.py | 2 +- compiler/tests/04_pdriver_test.py | 15 ++-- compiler/tests/04_pinv_10x_test.py | 2 +- compiler/tests/04_pinv_1x_beta_test.py | 2 +- compiler/tests/04_pinv_1x_test.py | 2 +- compiler/tests/04_pinv_2x_test.py | 2 +- compiler/tests/04_pinvbuf_test.py | 2 +- compiler/tests/04_pnand2_test.py | 2 +- compiler/tests/04_pnand3_test.py | 2 +- compiler/tests/04_pnor2_test.py | 2 +- compiler/tests/04_precharge_test.py | 4 +- compiler/tests/04_replica_pbitcell_test.py | 12 ++-- .../tests/04_single_level_column_mux_test.py | 11 +-- .../tests/06_hierarchical_decoder_test.py | 24 ++++--- .../06_hierarchical_predecode2x4_test.py | 4 +- .../06_hierarchical_predecode3x8_test.py | 4 +- .../07_single_level_column_mux_array_test.py | 18 ++--- compiler/tests/08_precharge_array_test.py | 13 ++-- compiler/tests/08_wordline_driver_test.py | 9 +-- compiler/tests/09_sense_amp_array_test.py | 12 ++-- compiler/tests/10_write_driver_array_test.py | 12 ++-- compiler/tests/13_delay_chain_test.py | 2 +- .../14_replica_bitline_multiport_test.py | 12 ++-- compiler/tests/14_replica_bitline_test.py | 4 +- compiler/tests/19_psingle_bank_test.py | 8 ++- 74 files changed, 410 insertions(+), 503 deletions(-) diff --git a/compiler/base/design.py b/compiler/base/design.py index f52aa100..d07e392a 100644 --- a/compiler/base/design.py +++ b/compiler/base/design.py @@ -6,7 +6,6 @@ import debug import os from globals import OPTS - class design(hierarchy_design): """ This is the same as the hierarchy_design class except it contains diff --git a/compiler/base/hierarchy_design.py b/compiler/base/hierarchy_design.py index 6031fe2f..7f30fb1c 100644 --- a/compiler/base/hierarchy_design.py +++ b/compiler/base/hierarchy_design.py @@ -17,20 +17,14 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout): name_map = [] def __init__(self, name): - try: - self.gds_file - except AttributeError: - self.gds_file = OPTS.openram_tech + "gds_lib/" + name + ".gds" - try: - self.sp_file - except AttributeError: - self.sp_file = OPTS.openram_tech + "sp_lib/" + name + ".sp" + self.gds_file = OPTS.openram_tech + "gds_lib/" + name + ".gds" + self.sp_file = OPTS.openram_tech + "sp_lib/" + name + ".sp" self.name = name hierarchy_layout.layout.__init__(self, name) hierarchy_spice.spice.__init__(self, name) - + # Check if the name already exists, if so, give an error # because each reference must be a unique name. # These modules ensure unique names or have no changes if they diff --git a/compiler/base/hierarchy_spice.py b/compiler/base/hierarchy_spice.py index 3fda8598..038cf0b7 100644 --- a/compiler/base/hierarchy_spice.py +++ b/compiler/base/hierarchy_spice.py @@ -16,11 +16,14 @@ class spice(): def __init__(self, name): self.name = name - self.mods = [] # Holds subckts/mods for this module - self.pins = [] # Holds the pins for this module - self.pin_type = {} # The type map of each pin: INPUT, OUTPUT, INOUT, POWER, GROUND + # Holds subckts/mods for this module + self.mods = [] + # Holds the pins for this module + self.pins = [] + # The type map of each pin: INPUT, OUTPUT, INOUT, POWER, GROUND # for each instance, this is the set of nets/nodes that map to the pins for this instance - # THIS MUST MATCH THE ORDER OF THE PINS (restriction imposed by the + self.pin_type = {} + # THE CONNECTIONS MUST MATCH THE ORDER OF THE PINS (restriction imposed by the # Spice format) self.conns = [] @@ -93,8 +96,8 @@ class spice(): from pprint import pformat modpins_string=pformat(self.insts[-1].mod.pins) argpins_string=pformat(args) - debug.error("Connections: {}".format(modpins_string)) - debug.error("Connections: {}".format(argpins_string)) + debug.error("Mod connections: {}".format(modpins_string)) + debug.error("Inst connections: {}".format(argpins_string)) debug.error("Number of net connections ({0}) does not match last instance ({1})".format(len(self.insts[-1].mod.pins), len(args)), 1) self.conns.append(args) diff --git a/compiler/bitcells/bitcell.py b/compiler/bitcells/bitcell.py index 0ac1c207..3c49a959 100644 --- a/compiler/bitcells/bitcell.py +++ b/compiler/bitcells/bitcell.py @@ -15,14 +15,15 @@ class bitcell(design.design): (width,height) = utils.get_libcell_size("cell_6t", GDS["unit"], layer["boundary"]) pin_map = utils.get_libcell_pins(pin_names, "cell_6t", GDS["unit"]) - def __init__(self): + def __init__(self, name=""): + # Ignore the name argument design.design.__init__(self, "cell_6t") debug.info(2, "Create bitcell") self.width = bitcell.width self.height = bitcell.height self.pin_map = bitcell.pin_map - + def analytical_delay(self, slew, load=0, swing = 0.5): # delay of bit cell is not like a driver(from WL) # so the slew used should be 0 diff --git a/compiler/bitcells/bitcell_1rw_1r.py b/compiler/bitcells/bitcell_1rw_1r.py index 2d740d2b..79dc734c 100644 --- a/compiler/bitcells/bitcell_1rw_1r.py +++ b/compiler/bitcells/bitcell_1rw_1r.py @@ -15,7 +15,8 @@ class bitcell_1rw_1r(design.design): (width,height) = utils.get_libcell_size("cell_1rw_1r", GDS["unit"], layer["boundary"]) pin_map = utils.get_libcell_pins(pin_names, "cell_1rw_1r", GDS["unit"]) - def __init__(self): + def __init__(self, name=""): + # Ignore the name argument design.design.__init__(self, "cell_1rw_1r") debug.info(2, "Create bitcell with 1RW and 1R Port") @@ -102,4 +103,4 @@ class bitcell_1rw_1r(design.design): #Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width. #FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed. access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"] - return 2*access_tx_cin \ No newline at end of file + return 2*access_tx_cin diff --git a/compiler/bitcells/pbitcell.py b/compiler/bitcells/pbitcell.py index 52156b39..b241471d 100644 --- a/compiler/bitcells/pbitcell.py +++ b/compiler/bitcells/pbitcell.py @@ -12,8 +12,7 @@ class pbitcell(design.design): with a variable number of read/write, write, and read ports """ - def __init__(self, replica_bitcell=False): - + def __init__(self, name, replica_bitcell=False): self.num_rw_ports = OPTS.num_rw_ports self.num_w_ports = OPTS.num_w_ports self.num_r_ports = OPTS.num_r_ports @@ -21,11 +20,6 @@ class pbitcell(design.design): self.replica_bitcell = replica_bitcell - if self.replica_bitcell: - name = "replica_pbitcell_{0}RW_{1}W_{2}R".format(self.num_rw_ports, self.num_w_ports, self.num_r_ports) - else: - name = "pbitcell_{0}RW_{1}W_{2}R".format(self.num_rw_ports, self.num_w_ports, self.num_r_ports) - design.design.__init__(self, name) debug.info(2, "create a multi-port bitcell with {0} rw ports, {1} w ports and {2} r ports".format(self.num_rw_ports, self.num_w_ports, diff --git a/compiler/bitcells/replica_bitcell.py b/compiler/bitcells/replica_bitcell.py index d896e29e..d8b8b76e 100644 --- a/compiler/bitcells/replica_bitcell.py +++ b/compiler/bitcells/replica_bitcell.py @@ -14,7 +14,8 @@ class replica_bitcell(design.design): (width,height) = utils.get_libcell_size("replica_cell_6t", GDS["unit"], layer["boundary"]) pin_map = utils.get_libcell_pins(pin_names, "replica_cell_6t", GDS["unit"]) - def __init__(self): + def __init__(self, name=""): + # Ignore the name argument design.design.__init__(self, "replica_cell_6t") debug.info(2, "Create replica bitcell object") @@ -27,4 +28,4 @@ class replica_bitcell(design.design): #This is a handmade cell so the value must be entered in the tech.py file or estimated. #Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width. access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"] - return 2*access_tx_cin \ No newline at end of file + return 2*access_tx_cin diff --git a/compiler/bitcells/replica_bitcell_1rw_1r.py b/compiler/bitcells/replica_bitcell_1rw_1r.py index f5151958..8f7b3b38 100644 --- a/compiler/bitcells/replica_bitcell_1rw_1r.py +++ b/compiler/bitcells/replica_bitcell_1rw_1r.py @@ -14,7 +14,8 @@ class replica_bitcell_1rw_1r(design.design): (width,height) = utils.get_libcell_size("replica_cell_1rw_1r", GDS["unit"], layer["boundary"]) pin_map = utils.get_libcell_pins(pin_names, "replica_cell_1rw_1r", GDS["unit"]) - def __init__(self): + def __init__(self, name=""): + # Ignore the name argument design.design.__init__(self, "replica_cell_1rw_1r") debug.info(2, "Create replica bitcell 1rw+1r object") @@ -28,4 +29,4 @@ class replica_bitcell_1rw_1r(design.design): #Calculated in the tech file by summing the widths of all the related gates and dividing by the minimum width. #FIXME: sizing is not accurate with the handmade cell. Change once cell widths are fixed. access_tx_cin = parameter["6T_access_size"]/drc["minwidth_tx"] - return 2*access_tx_cin \ No newline at end of file + return 2*access_tx_cin diff --git a/compiler/bitcells/replica_pbitcell.py b/compiler/bitcells/replica_pbitcell.py index 666d3646..4d2ecd70 100644 --- a/compiler/bitcells/replica_pbitcell.py +++ b/compiler/bitcells/replica_pbitcell.py @@ -3,21 +3,20 @@ import design from tech import drc, spice,parameter from vector import vector from globals import OPTS -from pbitcell import pbitcell +from sram_factory import factory class replica_pbitcell(design.design): """ Creates a replica bitcell using pbitcell """ - def __init__(self): - + def __init__(self, name): self.num_rw_ports = OPTS.num_rw_ports self.num_w_ports = OPTS.num_w_ports self.num_r_ports = OPTS.num_r_ports self.total_ports = self.num_rw_ports + self.num_w_ports + self.num_r_ports - design.design.__init__(self, "replica_pbitcell") + design.design.__init__(self, name) debug.info(1, "create a replica bitcell using pbitcell with {0} rw ports, {1} w ports and {2} r ports".format(self.num_rw_ports, self.num_w_ports, self.num_r_ports)) @@ -47,7 +46,7 @@ class replica_pbitcell(design.design): self.add_pin("gnd") def add_modules(self): - self.prbc = pbitcell(replica_bitcell=True) + self.prbc = factory.create(module_type="pbitcell",replica_bitcell=True) self.add_mod(self.prbc) self.height = self.prbc.height @@ -83,4 +82,4 @@ class replica_pbitcell(design.design): def get_wl_cin(self): """Return the relative capacitance of the access transistor gates""" #This module is made using a pbitcell. Get the cin from that module - return self.prbc.get_wl_cin() \ No newline at end of file + return self.prbc.get_wl_cin() diff --git a/compiler/globals.py b/compiler/globals.py index a6360e24..0c73e89d 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -130,6 +130,9 @@ def init_openram(config_file, is_unit_test=True): init_paths() + from sram_factory import factory + factory.reset() + # Reset the static duplicate name checker for unit tests. import hierarchy_design hierarchy_design.hierarchy_design.name_map=[] diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index a0508b51..77cde2cb 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -6,9 +6,7 @@ import math from math import log,sqrt,ceil import contact import pgates -from pinv import pinv -from pnand2 import pnand2 -from pnor2 import pnor2 +from sram_factory import factory from vector import vector from globals import OPTS @@ -396,25 +394,14 @@ class bank(design.design): def add_modules(self): """ Add all the modules using the class loader """ - mod_list = ["bitcell", "decoder", "wordline_driver", - "bitcell_array", "sense_amp_array", "precharge_array", - "column_mux_array", "write_driver_array", - "dff", "bank_select"] - from importlib import reload - for mod_name in mod_list: - config_mod_name = getattr(OPTS, mod_name) - class_file = reload(__import__(config_mod_name)) - mod_class = getattr(class_file , config_mod_name) - setattr (self, "mod_"+mod_name, mod_class) - - - self.bitcell_array = self.mod_bitcell_array(cols=self.num_cols, - rows=self.num_rows) + self.bitcell_array = factory.create(module_type="bitcell_array", + cols=self.num_cols, + rows=self.num_rows) self.add_mod(self.bitcell_array) # create arrays of bitline and bitline_bar names for read, write, or all ports - self.bitcell = self.mod_bitcell() + self.bitcell = factory.create(module_type="bitcell") self.bl_names = self.bitcell.list_all_bl_names() self.br_names = self.bitcell.list_all_br_names() self.wl_names = self.bitcell.list_all_wl_names() @@ -423,7 +410,11 @@ class bank(design.design): self.precharge_array = [] for port in self.all_ports: if port in self.read_ports: - self.precharge_array.append(self.mod_precharge_array(columns=self.num_cols, bitcell_bl=self.bl_names[port], bitcell_br=self.br_names[port])) + temp_pre = factory.create(module_type="precharge_array", + columns=self.num_cols, + bitcell_bl=self.bl_names[port], + bitcell_br=self.br_names[port]) + self.precharge_array.append(temp_pre) self.add_mod(self.precharge_array[port]) else: self.precharge_array.append(None) @@ -431,32 +422,38 @@ class bank(design.design): if self.col_addr_size > 0: self.column_mux_array = [] for port in self.all_ports: - self.column_mux_array.append(self.mod_column_mux_array(columns=self.num_cols, - word_size=self.word_size, - bitcell_bl=self.bl_names[port], - bitcell_br=self.br_names[port])) + temp_col = factory.create(module_type="column_mux_array", + columns=self.num_cols, + word_size=self.word_size, + bitcell_bl=self.bl_names[port], + bitcell_br=self.br_names[port]) + self.column_mux_array.append(temp_col) self.add_mod(self.column_mux_array[port]) - self.sense_amp_array = self.mod_sense_amp_array(word_size=self.word_size, - words_per_row=self.words_per_row) + self.sense_amp_array = factory.create(module_type="sense_amp_array", + word_size=self.word_size, + words_per_row=self.words_per_row) self.add_mod(self.sense_amp_array) - self.write_driver_array = self.mod_write_driver_array(columns=self.num_cols, - word_size=self.word_size) + self.write_driver_array = factory.create(module_type="write_driver_array", + columns=self.num_cols, + word_size=self.word_size) self.add_mod(self.write_driver_array) - self.row_decoder = self.mod_decoder(rows=self.num_rows) + self.row_decoder = factory.create(module_type="decoder", + rows=self.num_rows) self.add_mod(self.row_decoder) - self.wordline_driver = self.mod_wordline_driver(rows=self.num_rows) + self.wordline_driver = factory.create(module_type="wordline_driver", + rows=self.num_rows) self.add_mod(self.wordline_driver) - self.inv = pinv() + self.inv = factory.create(module_type="pinv") self.add_mod(self.inv) if(self.num_banks > 1): - self.bank_select = self.mod_bank_select() + self.bank_select = factory.create(module_type="bank_select") self.add_mod(self.bank_select) @@ -693,18 +690,17 @@ class bank(design.design): """ Create a 2:4 or 3:8 column address decoder. """ + + dff = factory.create(module_type="dff") if self.col_addr_size == 0: return elif self.col_addr_size == 1: - from pinvbuf import pinvbuf - self.column_decoder = pinvbuf(height=self.mod_dff.height) + self.column_decoder = factory.create(module_type="pinvbuf", height=dff.height) elif self.col_addr_size == 2: - from hierarchical_predecode2x4 import hierarchical_predecode2x4 as pre2x4 - self.column_decoder = pre2x4(height=self.mod_dff.height) + self.column_decoder = factory.create(module_type="hierarchical_predecode2x4", height=dff.height) elif self.col_addr_size == 3: - from hierarchical_predecode3x8 import hierarchical_predecode3x8 as pre3x8 - self.column_decoder = pre3x8(height=self.mod_dff.height) + self.column_decoder = factory.create(module_type="hierarchical_predecode3x8", height=dff.height) else: # No error checking before? debug.error("Invalid column decoder?",-1) @@ -1273,4 +1269,4 @@ class bank(design.design): """Get the relative capacitance of all the sense amp enable connections in the bank""" #Current bank only uses sen as an enable for the sense amps. total_sen_cin = self.sense_amp_array.get_en_cin() - return total_sen_cin \ No newline at end of file + return total_sen_cin diff --git a/compiler/modules/bank_select.py b/compiler/modules/bank_select.py index 7141de2a..8e44dfa2 100644 --- a/compiler/modules/bank_select.py +++ b/compiler/modules/bank_select.py @@ -7,6 +7,7 @@ from pinv import pinv from pnand2 import pnand2 from pnor2 import pnor2 from vector import vector +from sram_factory import factory from globals import OPTS class bank_select(design.design): @@ -62,28 +63,25 @@ class bank_select(design.design): def add_modules(self): """ Create modules for later instantiation """ - from importlib import reload - c = reload(__import__(OPTS.bitcell)) - self.mod_bitcell = getattr(c, OPTS.bitcell) - self.bitcell = self.mod_bitcell() + self.bitcell = factory.create(module_type="bitcell") height = self.bitcell.height + drc("poly_to_active") # 1x Inverter - self.inv_sel = pinv(height=height) + self.inv_sel = factory.create(module_type="pinv", height=height) self.add_mod(self.inv_sel) # 4x Inverter - self.inv = self.inv4x = pinv(4) + self.inv4x = factory.create(module_type="pinv", height=height, size=4) self.add_mod(self.inv4x) - self.nor2 = pnor2(height=height) + self.nor2 = factory.create(module_type="pnor2", height=height) self.add_mod(self.nor2) - self.inv4x_nor = pinv(size=4, height=height) + self.inv4x_nor = factory.create(module_type="pinv", height=height, size=4) self.add_mod(self.inv4x_nor) - self.nand2 = pnand2() + self.nand2 = factory.create(module_type="pnand2") self.add_mod(self.nand2) def calculate_module_offsets(self): @@ -94,7 +92,7 @@ class bank_select(design.design): self.xoffset_bank_sel_inv = 0 self.xoffset_inputs = 0 - self.yoffset_maxpoint = self.num_control_lines * self.inv.height + self.yoffset_maxpoint = self.num_control_lines * self.inv4x.height # Include the M1 pitches for the supply rails and spacing self.height = self.yoffset_maxpoint + 2*self.m1_pitch self.width = self.xoffset_inv + self.inv4x.width @@ -170,10 +168,10 @@ class bank_select(design.design): if i == 0: y_offset = 0 else: - y_offset = self.inv4x_nor.height + self.inv.height * (i-1) + y_offset = self.inv4x_nor.height + self.inv4x.height * (i-1) if i%2: - y_offset += self.inv.height + y_offset += self.inv4x.height mirror = "MX" else: mirror = "" @@ -223,7 +221,7 @@ class bank_select(design.design): self.add_label_pin(text="bank_sel_bar", layer="metal2", offset=vector(xoffset_bank_sel_bar, 0), - height=self.inv.height) + height=self.inv4x.height) self.add_via_center(layers=("metal1","via1","metal2"), offset=bank_sel_bar_pin.rc()) diff --git a/compiler/modules/bitcell_array.py b/compiler/modules/bitcell_array.py index 6032fc19..166437fa 100644 --- a/compiler/modules/bitcell_array.py +++ b/compiler/modules/bitcell_array.py @@ -3,8 +3,7 @@ import design from tech import drc, spice from vector import vector from globals import OPTS - -unique_id = 1 +from sram_factory import factory class bitcell_array(design.design): """ @@ -12,13 +11,7 @@ class bitcell_array(design.design): and word line is connected by abutment. Connects the word lines and bit lines. """ - unique_id = 1 - - def __init__(self, cols, rows, name=""): - - if name == "": - name = "bitcell_array_{0}x{1}_{2}".format(rows,cols,bitcell_array.unique_id) - bitcell_array.unique_id += 1 + def __init__(self, cols, rows, name): design.design.__init__(self, name) debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols)) @@ -83,11 +76,7 @@ class bitcell_array(design.design): def add_modules(self): """ Add the modules used in this design """ - - from importlib import reload - c = reload(__import__(OPTS.bitcell)) - self.mod_bitcell = getattr(c, OPTS.bitcell) - self.cell = self.mod_bitcell() + self.cell = factory.create(module_type="bitcell") self.add_mod(self.cell) def create_instances(self): @@ -210,4 +199,4 @@ class bitcell_array(design.design): #A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns bitcell_wl_cin = self.cell.get_wl_cin() total_cin = bitcell_wl_cin * self.column_size - return total_cin \ No newline at end of file + return total_cin diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index c30d91a0..52af5bbb 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -3,13 +3,7 @@ import design from tech import drc, parameter import debug import contact -from pinv import pinv -from pbuf import pbuf -from pand2 import pand2 -from pnand2 import pnand2 -from pinvbuf import pinvbuf -from dff_buf import dff_buf -from dff_buf_array import dff_buf_array +from sram_factory import factory import math from vector import vector from globals import OPTS @@ -73,46 +67,56 @@ class control_logic(design.design): def add_modules(self): """ Add all the required modules """ - dff = dff_buf() + dff = factory.create(module_type="dff_buf") dff_height = dff.height - self.ctrl_dff_array = dff_buf_array(rows=self.num_control_signals,columns=1) + self.ctrl_dff_array = factory.create(module_type="dff_buf_array", + rows=self.num_control_signals, + columns=1) + self.add_mod(self.ctrl_dff_array) - self.and2 = pand2(size=4,height=dff_height) + self.and2 = factory.create(module_type="pand2", + size=4, + height=dff_height) self.add_mod(self.and2) # Special gates: inverters for buffering # Size the clock for the number of rows (fanout) clock_driver_size = max(1,int(self.num_rows/4)) - self.clkbuf = pbuf(size=clock_driver_size, height=dff_height) + self.clkbuf = factory.create(module_type="pbuf", + size=clock_driver_size, + height=dff_height) + self.add_mod(self.clkbuf) - self.buf16 = pbuf(size=16, height=dff_height) + self.buf16 = factory.create(module_type="pbuf", + size=16, + height=dff_height) self.add_mod(self.buf16) - self.buf8 = pbuf(size=8, height=dff_height) + self.buf8 = factory.create(module_type="pbuf", + size=8, + height=dff_height) self.add_mod(self.buf8) - self.inv = self.inv1 = pinv(size=1, height=dff_height) + self.inv = self.inv1 = factory.create(module_type="pinv", + size=1, + height=dff_height) self.add_mod(self.inv1) - self.inv8 = pinv(size=8, height=dff_height) + self.inv8 = factory.create(module_type="pinv", + size=8, + height=dff_height) self.add_mod(self.inv8) - # self.inv2 = pinv(size=4, height=dff_height) - # self.add_mod(self.inv2) - #self.inv16 = pinv(size=16, height=dff_height) - #self.add_mod(self.inv16) - if (self.port_type == "rw") or (self.port_type == "r"): - from importlib import reload - c = reload(__import__(OPTS.replica_bitline)) - replica_bitline = getattr(c, OPTS.replica_bitline) - delay_stages_heuristic, delay_fanout_heuristic = self.get_heuristic_delay_chain_size() bitcell_loads = int(math.ceil(self.num_rows / 2.0)) - self.replica_bitline = replica_bitline([delay_fanout_heuristic]*delay_stages_heuristic, bitcell_loads, name="replica_bitline_"+self.port_type) + self.replica_bitline = factory.create(module_type="replica_bitline", + delay_fanout_list=[delay_fanout_heuristic]*delay_stages_heuristic, + bitcell_loads=bitcell_loads) + if self.sram != None: self.set_sen_wl_delays() @@ -124,8 +128,10 @@ class control_logic(design.design): #This resizes based on total delay. delay_stages, delay_fanout = self.get_dynamic_delay_chain_size(delay_stages_heuristic, delay_fanout_heuristic) - self.replica_bitline = replica_bitline([delay_fanout]*delay_stages, bitcell_loads, name="replica_bitline_resized_"+self.port_type) - + self.replica_bitline = factory.create(module_type="replica_bitline", + delay_fanout_list=[delay_fanout]*delay_stages, + bitcell_loads=bitcell_loads) + self.sen_delay_rise,self.sen_delay_fall = self.get_delays_to_sen() #get the new timing self.add_mod(self.replica_bitline) @@ -853,4 +859,4 @@ class control_logic(design.design): last_stage_rise = stage_effort_list[-1].is_rise return stage_effort_list - \ No newline at end of file + diff --git a/compiler/modules/delay_chain.py b/compiler/modules/delay_chain.py index 722328d1..1478dbfc 100644 --- a/compiler/modules/delay_chain.py +++ b/compiler/modules/delay_chain.py @@ -1,10 +1,10 @@ import debug import design from tech import drc -from pinv import pinv from contact import contact from vector import vector from globals import OPTS +from sram_factory import factory class delay_chain(design.design): """ @@ -13,12 +13,8 @@ class delay_chain(design.design): Usually, this will be constant, but it could have varied fanout. """ - unique_id = 1 - - def __init__(self, fanout_list, name="delay_chain"): + def __init__(self, name, fanout_list): """init function""" - name = name+"_{}".format(delay_chain.unique_id) - delay_chain.unique_id += 1 design.design.__init__(self, name) # Two fanouts are needed so that we can route the vdd/gnd connections @@ -57,7 +53,7 @@ class delay_chain(design.design): self.add_pin("gnd") def add_modules(self): - self.inv = pinv(route_output=False) + self.inv = factory.create(module_type="pinv", route_output=False) self.add_mod(self.inv) def create_inverters(self): @@ -238,4 +234,4 @@ class delay_chain(design.design): stage_effort_list.append(stage) last_stage_is_rise = stage.is_rise - return stage_effort_list \ No newline at end of file + return stage_effort_list diff --git a/compiler/modules/dff_array.py b/compiler/modules/dff_array.py index 25ef3090..215d2884 100644 --- a/compiler/modules/dff_array.py +++ b/compiler/modules/dff_array.py @@ -3,6 +3,7 @@ import design from tech import drc from math import log from vector import vector +from sram_factory import factory from globals import OPTS class dff_array(design.design): @@ -38,10 +39,7 @@ class dff_array(design.design): self.DRC_LVS() def add_modules(self): - from importlib import reload - c = reload(__import__(OPTS.dff)) - self.mod_dff = getattr(c, OPTS.dff) - self.dff = self.mod_dff("dff") + self.dff = factory.create(module_type="dff") self.add_mod(self.dff) def add_pins(self): @@ -61,7 +59,7 @@ class dff_array(design.design): for col in range(self.columns): name = "dff_r{0}_c{1}".format(row,col) self.dff_insts[row,col]=self.add_inst(name=name, - mod=self.dff) + mod=self.dff) self.connect_inst([self.get_din_name(row,col), self.get_dout_name(row,col), "clk", @@ -162,4 +160,4 @@ class dff_array(design.design): """Return the total capacitance (in relative units) that the clock is loaded by in the dff array""" dff_clk_cin = self.dff.get_clk_cin() total_cin = dff_clk_cin * self.rows * self.columns - return total_cin \ No newline at end of file + return total_cin diff --git a/compiler/modules/dff_buf.py b/compiler/modules/dff_buf.py index 9ff89603..4f6fff11 100644 --- a/compiler/modules/dff_buf.py +++ b/compiler/modules/dff_buf.py @@ -4,7 +4,7 @@ from tech import drc,parameter from math import log from vector import vector from globals import OPTS -from pinv import pinv +from sram_factory import factory class dff_buf(design.design): """ @@ -50,16 +50,17 @@ class dff_buf(design.design): self.DRC_LVS() def add_modules(self): - from importlib import reload - c = reload(__import__(OPTS.dff)) - self.mod_dff = getattr(c, OPTS.dff) - self.dff = self.mod_dff("dff") + self.dff = factory.create(module_type="dff") self.add_mod(self.dff) - self.inv1 = pinv(size=self.inv1_size,height=self.dff.height) + self.inv1 = factory.create(module_type="pinv", + size=self.inv1_size, + height=self.dff.height) self.add_mod(self.inv1) - self.inv2 = pinv(size=self.inv2_size,height=self.dff.height) + self.inv2 = factory.create(module_type="pinv", + size=self.inv2_size, + height=self.dff.height) self.add_mod(self.inv2) @@ -182,4 +183,4 @@ class dff_buf(design.design): #This is a handmade cell so the value must be entered in the tech.py file or estimated. #Calculated in the tech file by summing the widths of all the gates and dividing by the minimum width. #FIXME: Dff changed in a past commit. The parameter need to be updated. - return parameter["dff_clk_cin"] \ No newline at end of file + return parameter["dff_clk_cin"] diff --git a/compiler/modules/dff_buf_array.py b/compiler/modules/dff_buf_array.py index 8097f207..4d655a64 100644 --- a/compiler/modules/dff_buf_array.py +++ b/compiler/modules/dff_buf_array.py @@ -4,7 +4,7 @@ from tech import drc from math import log from vector import vector from globals import OPTS -import dff_buf +from sram_factory import factory class dff_buf_array(design.design): """ @@ -54,7 +54,9 @@ class dff_buf_array(design.design): self.add_pin("gnd") def add_modules(self): - self.dff = dff_buf.dff_buf(self.inv1_size, self.inv2_size) + self.dff = factory.create(module_type="dff_buf", + inv1_size=self.inv1_size, + inv2_size=self.inv2_size) self.add_mod(self.dff) def create_dff_array(self): @@ -189,4 +191,4 @@ class dff_buf_array(design.design): """Return the total capacitance (in relative units) that the clock is loaded by in the dff array""" dff_clk_cin = self.dff.get_clk_cin() total_cin = dff_clk_cin * self.rows * self.columns - return total_cin \ No newline at end of file + return total_cin diff --git a/compiler/modules/dff_inv.py b/compiler/modules/dff_inv.py index aebe49c2..f8ff00bf 100644 --- a/compiler/modules/dff_inv.py +++ b/compiler/modules/dff_inv.py @@ -55,13 +55,12 @@ class dff_inv(design.design): self.add_pin("gnd") def add_modules(self): - from importlib import reload - c = reload(__import__(OPTS.dff)) - self.mod_dff = getattr(c, OPTS.dff) - self.dff = self.mod_dff("dff") + self.dff = dff_inv.dff_inv(self.inv_size) self.add_mod(self.dff) - self.inv1 = pinv(size=self.inv_size,height=self.dff.height) + self.inv1 = factory.create(module_type="pinv", + size=self.inv_size, + height=self.dff.height) self.add_mod(self.inv1) def create_modules(self): @@ -152,4 +151,4 @@ class dff_inv(design.design): def get_clk_cin(self): """Return the total capacitance (in relative units) that the clock is loaded by in the dff""" - return self.dff.get_clk_cin() \ No newline at end of file + return self.dff.get_clk_cin() diff --git a/compiler/modules/dff_inv_array.py b/compiler/modules/dff_inv_array.py index 8985b99a..629a1d67 100644 --- a/compiler/modules/dff_inv_array.py +++ b/compiler/modules/dff_inv_array.py @@ -42,7 +42,7 @@ class dff_inv_array(design.design): self.DRC_LVS() def add_modules(self): - self.dff = dff_inv.dff_inv(self.inv_size) + self.dff = factory.create(module_type="dff") self.add_mod(self.dff) def add_pins(self): @@ -189,4 +189,4 @@ class dff_inv_array(design.design): """Return the total capacitance (in relative units) that the clock is loaded by in the dff array""" dff_clk_cin = self.dff.get_clk_cin() total_cin = dff_clk_cin * self.rows * self.columns - return total_cin \ No newline at end of file + return total_cin diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py index 32ed6d7c..4bbb6aca 100644 --- a/compiler/modules/hierarchical_decoder.py +++ b/compiler/modules/hierarchical_decoder.py @@ -4,12 +4,8 @@ import design from math import log from math import sqrt import math -import contact -from pnand2 import pnand2 -from pnand3 import pnand3 -from pinv import pinv -from hierarchical_predecode2x4 import hierarchical_predecode2x4 as pre2x4 -from hierarchical_predecode3x8 import hierarchical_predecode3x8 as pre3x8 +import contact +from sram_factory import factory from vector import vector from globals import OPTS @@ -17,11 +13,8 @@ class hierarchical_decoder(design.design): """ Dynamically generated hierarchical decoder. """ - unique_id = 1 - - def __init__(self, rows, height=None): - design.design.__init__(self, "hierarchical_decoder_{0}rows_{1}".format(rows,hierarchical_decoder.unique_id)) - hierarchical_decoder.unique_id += 1 + def __init__(self, name, rows, height=None): + design.design.__init__(self, name) self.NAND_FORMAT = "DEC_NAND_{0}" self.INV_FORMAT = "DEC_INV_{0}" @@ -57,21 +50,26 @@ class hierarchical_decoder(design.design): self.DRC_LVS() def add_modules(self): - self.inv = pinv(height=self.cell_height) + self.inv = factory.create(module_type="pinv", + height=self.cell_height) self.add_mod(self.inv) - self.nand2 = pnand2(height=self.cell_height) + self.nand2 = factory.create(module_type="pnand2", + height=self.cell_height) self.add_mod(self.nand2) - self.nand3 = pnand3(height=self.cell_height) + self.nand3 = factory.create(module_type="pnand3", + height=self.cell_height) self.add_mod(self.nand3) self.add_decoders() def add_decoders(self): """ Create the decoders based on the number of pre-decodes """ - self.pre2_4 = pre2x4(height=self.cell_height) + self.pre2_4 = factory.create(module_type="hierarchical_predecode2x4", + height=self.cell_height) self.add_mod(self.pre2_4) - self.pre3_8 = pre3x8(height=self.cell_height) + self.pre3_8 = factory.create(module_type="hierarchical_predecode3x8", + height=self.cell_height) self.add_mod(self.pre3_8) def determine_predecodes(self,num_inputs): diff --git a/compiler/modules/hierarchical_predecode.py b/compiler/modules/hierarchical_predecode.py index 7dfd443d..147c3018 100644 --- a/compiler/modules/hierarchical_predecode.py +++ b/compiler/modules/hierarchical_predecode.py @@ -3,24 +3,19 @@ import design import math from tech import drc import contact -from pinv import pinv from vector import vector from globals import OPTS -from pnand2 import pnand2 -from pnand3 import pnand3 +from sram_factory import factory class hierarchical_predecode(design.design): """ Pre 2x4 and 3x8 decoder shared code. """ - unique_id = 1 - - def __init__(self, input_number, height=None): + def __init__(self, name, input_number, height=None): self.number_of_inputs = input_number self.cell_height = height self.number_of_outputs = int(math.pow(2, self.number_of_inputs)) - design.design.__init__(self, name="pre{0}x{1}_{2}".format(self.number_of_inputs,self.number_of_outputs,hierarchical_predecode.unique_id)) - hierarchical_predecode.unique_id += 1 + design.design.__init__(self, name) def add_pins(self): for k in range(self.number_of_inputs): @@ -33,7 +28,8 @@ class hierarchical_predecode(design.design): def add_modules(self): """ Add the INV and NAND gate modules """ - self.inv = pinv(height=self.cell_height) + self.inv = factory.create(module_type="pinv", + height=self.cell_height) self.add_mod(self.inv) self.add_nand(self.number_of_inputs) @@ -42,9 +38,11 @@ class hierarchical_predecode(design.design): def add_nand(self,inputs): """ Create the NAND for the predecode input stage """ if inputs==2: - self.nand = pnand2(height=self.cell_height) + self.nand = factory.create(module_type="pnand2", + height=self.cell_height) elif inputs==3: - self.nand = pnand3(height=self.cell_height) + self.nand = factory.create(module_type="pnand3", + height=self.cell_height) else: debug.error("Invalid number of predecode inputs: {}".format(inputs),-1) diff --git a/compiler/modules/hierarchical_predecode2x4.py b/compiler/modules/hierarchical_predecode2x4.py index 918172ea..83e93f85 100644 --- a/compiler/modules/hierarchical_predecode2x4.py +++ b/compiler/modules/hierarchical_predecode2x4.py @@ -9,8 +9,8 @@ class hierarchical_predecode2x4(hierarchical_predecode): """ Pre 2x4 decoder used in hierarchical_decoder. """ - def __init__(self, height=None): - hierarchical_predecode.__init__(self, 2, height) + def __init__(self, name, height=None): + hierarchical_predecode.__init__(self, name, 2, height) self.create_netlist() if not OPTS.netlist_only: diff --git a/compiler/modules/hierarchical_predecode3x8.py b/compiler/modules/hierarchical_predecode3x8.py index 88bbbcd7..109e8160 100644 --- a/compiler/modules/hierarchical_predecode3x8.py +++ b/compiler/modules/hierarchical_predecode3x8.py @@ -9,8 +9,8 @@ class hierarchical_predecode3x8(hierarchical_predecode): """ Pre 3x8 decoder used in hierarchical_decoder. """ - def __init__(self, height=None): - hierarchical_predecode.__init__(self, 3, height) + def __init__(self, name, height=None): + hierarchical_predecode.__init__(self, name, 3, height) self.create_netlist() if not OPTS.netlist_only: diff --git a/compiler/modules/multibank.py b/compiler/modules/multibank.py index d402b145..1b9e6194 100644 --- a/compiler/modules/multibank.py +++ b/compiler/modules/multibank.py @@ -5,12 +5,8 @@ import design import math from math import log,sqrt,ceil import contact -from pinv import pinv -from pnand2 import pnand2 -from pnor2 import pnor2 from vector import vector -from pinvbuf import pinvbuf - +from sram_factory import factory from globals import OPTS class multibank(design.design): @@ -21,21 +17,8 @@ class multibank(design.design): This module includes the tristate and bank select logic. """ - def __init__(self, word_size, num_words, words_per_row, num_banks=1, name=""): + def __init__(self, name, word_size, num_words, words_per_row, num_banks=1): - mod_list = ["tri_gate", "bitcell", "decoder", "wordline_driver", - "bitcell_array", "sense_amp_array", "precharge_array", - "column_mux_array", "write_driver_array", "tri_gate_array", - "dff", "bank_select"] - from importlib import reload - for mod_name in mod_list: - config_mod_name = getattr(OPTS, mod_name) - class_file = reload(__import__(config_mod_name)) - mod_class = getattr(class_file , config_mod_name) - setattr (self, "mod_"+mod_name, mod_class) - - if name == "": - name = "bank_{0}_{1}".format(word_size, num_words) design.design.__init__(self, name) debug.info(2, "create sram of size {0} with {1} words".format(word_size,num_words)) diff --git a/compiler/modules/precharge_array.py b/compiler/modules/precharge_array.py index 8bb66cda..ff84cfe6 100644 --- a/compiler/modules/precharge_array.py +++ b/compiler/modules/precharge_array.py @@ -2,7 +2,7 @@ import design import debug from tech import drc from vector import vector -from precharge import precharge +from sram_factory import factory from globals import OPTS class precharge_array(design.design): @@ -11,11 +11,7 @@ class precharge_array(design.design): of bit line columns, height is the height of the bit-cell array. """ - unique_id = 1 - - def __init__(self, columns, size=1, bitcell_bl="bl", bitcell_br="br"): - name = "precharge_array_{}".format(precharge_array.unique_id) - precharge_array.unique_id += 1 + def __init__(self, name, columns, size=1, bitcell_bl="bl", bitcell_br="br"): design.design.__init__(self, name) debug.info(1, "Creating {0}".format(self.name)) @@ -50,10 +46,12 @@ class precharge_array(design.design): self.DRC_LVS() def add_modules(self): - self.pc_cell = precharge(name="precharge", - size=self.size, - bitcell_bl=self.bitcell_bl, - bitcell_br=self.bitcell_br) + self.pc_cell = factory.create(module_type="precharge", + size=self.size, + bitcell_bl=self.bitcell_bl, + bitcell_br=self.bitcell_br) + + self.add_mod(self.pc_cell) @@ -107,4 +105,4 @@ class precharge_array(design.design): """Get the relative capacitance of all the clk connections in the precharge array""" #Assume single port precharge_en_cin = self.pc_cell.get_en_cin() - return precharge_en_cin*self.columns \ No newline at end of file + return precharge_en_cin*self.columns diff --git a/compiler/modules/replica_bitline.py b/compiler/modules/replica_bitline.py index 8538fbee..614e6d42 100644 --- a/compiler/modules/replica_bitline.py +++ b/compiler/modules/replica_bitline.py @@ -1,10 +1,8 @@ import debug import design from tech import drc -from pinv import pinv import contact -from bitcell_array import bitcell_array -from ptx import ptx +from sram_factory import factory from vector import vector from globals import OPTS @@ -15,7 +13,7 @@ class replica_bitline(design.design): line and rows is the height of the replica bit loads. """ - def __init__(self, delay_fanout_list, bitcell_loads, name="replica_bitline"): + def __init__(self, name, delay_fanout_list, bitcell_loads): design.design.__init__(self, name) self.bitcell_loads = bitcell_loads @@ -78,29 +76,25 @@ class replica_bitline(design.design): def add_modules(self): """ Add the modules for later usage """ - from importlib import reload - #g = reload(__import__(OPTS.delay_chain)) - #self.mod_delay_chain = getattr(g, OPTS.delay_chain) - - g = reload(__import__(OPTS.replica_bitcell)) - self.mod_replica_bitcell = getattr(g, OPTS.replica_bitcell) - - self.bitcell = self.replica_bitcell = self.mod_replica_bitcell() - self.add_mod(self.bitcell) + self.replica_bitcell = factory.create(module_type="replica_bitcell") + self.add_mod(self.replica_bitcell) # This is the replica bitline load column that is the height of our array - self.rbl = bitcell_array(cols=1, rows=self.bitcell_loads) + self.rbl = factory.create(module_type="bitcell_array", + cols=1, + rows=self.bitcell_loads) self.add_mod(self.rbl) # FIXME: The FO and depth of this should be tuned - from delay_chain import delay_chain - self.delay_chain = delay_chain(self.delay_fanout_list) + self.delay_chain = factory.create(module_type="delay_chain", + fanout_list=self.delay_fanout_list) self.add_mod(self.delay_chain) - self.inv = pinv() + self.inv = factory.create(module_type="pinv") self.add_mod(self.inv) - self.access_tx = ptx(tx_type="pmos") + self.access_tx = factory.create(module_type="ptx", + tx_type="pmos") self.add_mod(self.access_tx) def create_instances(self): @@ -132,7 +126,6 @@ class replica_bitline(design.design): temp.append("vdd") temp.append("gnd") self.connect_inst(temp) - #self.connect_inst(["bl_0", "br_0", "delayed_en", "vdd", "gnd"]) self.rbl_inst=self.add_inst(name="load", mod=self.rbl) @@ -631,4 +624,4 @@ class replica_bitline(design.design): access_tx_cin = self.access_tx.get_cin() rbc_cin = self.replica_bitcell.get_wl_cin() return access_tx_cin + rbc_cin - \ No newline at end of file + diff --git a/compiler/modules/sense_amp_array.py b/compiler/modules/sense_amp_array.py index 806acf71..3209377b 100644 --- a/compiler/modules/sense_amp_array.py +++ b/compiler/modules/sense_amp_array.py @@ -1,6 +1,7 @@ import design from tech import drc from vector import vector +from sram_factory import factory import debug from globals import OPTS @@ -10,8 +11,8 @@ class sense_amp_array(design.design): Dynamically generated sense amp array for all bitlines. """ - def __init__(self, word_size, words_per_row): - design.design.__init__(self, "sense_amp_array") + def __init__(self, name, word_size, words_per_row): + design.design.__init__(self, name) debug.info(1, "Creating {0}".format(self.name)) self.word_size = word_size @@ -51,17 +52,13 @@ class sense_amp_array(design.design): self.add_pin("gnd") def add_modules(self): - from importlib import reload - c = reload(__import__(OPTS.sense_amp)) - self.mod_sense_amp = getattr(c, OPTS.sense_amp) - self.amp = self.mod_sense_amp("sense_amp") + self.amp = factory.create(module_type="sense_amp") + self.add_mod(self.amp) # This is just used for measurements, # so don't add the module - c = reload(__import__(OPTS.bitcell)) - self.mod_bitcell = getattr(c, OPTS.bitcell) - self.bitcell = self.mod_bitcell() + self.bitcell = factory.create(module_type="bitcell") def create_sense_amp_array(self): self.local_insts = [] @@ -143,4 +140,4 @@ class sense_amp_array(design.design): def get_en_cin(self): """Get the relative capacitance of all the sense amp enable connections in the array""" sense_amp_en_cin = self.amp.get_en_cin() - return sense_amp_en_cin * self.words_per_row \ No newline at end of file + return sense_amp_en_cin * self.words_per_row diff --git a/compiler/modules/single_level_column_mux_array.py b/compiler/modules/single_level_column_mux_array.py index 699e1d85..9ce95c66 100644 --- a/compiler/modules/single_level_column_mux_array.py +++ b/compiler/modules/single_level_column_mux_array.py @@ -1,11 +1,11 @@ from math import log import design -from single_level_column_mux import single_level_column_mux import contact from tech import drc import debug import math from vector import vector +from sram_factory import factory from globals import OPTS class single_level_column_mux_array(design.design): @@ -14,11 +14,7 @@ class single_level_column_mux_array(design.design): Array of column mux to read the bitlines through the 6T. """ - unique_id = 1 - - def __init__(self, columns, word_size, bitcell_bl="bl", bitcell_br="br"): - name="single_level_column_mux_array_{}".format(single_level_column_mux_array.unique_id) - single_level_column_mux_array.unique_id += 1 + def __init__(self, name, columns, word_size, bitcell_bl="bl", bitcell_br="br"): design.design.__init__(self, name) debug.info(1, "Creating {0}".format(self.name)) self.columns = columns @@ -61,7 +57,9 @@ class single_level_column_mux_array(design.design): def add_modules(self): - self.mux = single_level_column_mux(bitcell_bl=self.bitcell_bl, bitcell_br=self.bitcell_br) + self.mux = factory.create(module_type="single_level_column_mux", + bitcell_bl=self.bitcell_bl, + bitcell_br=self.bitcell_br) self.add_mod(self.mux) diff --git a/compiler/modules/tri_gate_array.py b/compiler/modules/tri_gate_array.py index 5ca992b3..d56e9c96 100644 --- a/compiler/modules/tri_gate_array.py +++ b/compiler/modules/tri_gate_array.py @@ -2,6 +2,7 @@ import debug from tech import drc import design from vector import vector +from sram_factory import factory from globals import OPTS class tri_gate_array(design.design): @@ -36,10 +37,7 @@ class tri_gate_array(design.design): self.DRC_LVS() def add_modules(self): - from importlib import reload - c = reload(__import__(OPTS.tri_gate)) - self.mod_tri_gate = getattr(c, OPTS.tri_gate) - self.tri = self.mod_tri_gate("tri_gate") + self.tri = factory.create(module_type="tri_gate") self.add_mod(self.tri) def add_pins(self): diff --git a/compiler/modules/wordline_driver.py b/compiler/modules/wordline_driver.py index af82fbc5..021b76d1 100644 --- a/compiler/modules/wordline_driver.py +++ b/compiler/modules/wordline_driver.py @@ -5,9 +5,8 @@ import contact from math import log from math import sqrt import math -from pinv import pinv -from pnand2 import pnand2 from vector import vector +from sram_factory import factory from globals import OPTS class wordline_driver(design.design): @@ -16,8 +15,8 @@ class wordline_driver(design.design): Generates the wordline-driver to drive the bitcell """ - def __init__(self, rows): - design.design.__init__(self, "wordline_driver") + def __init__(self, name, rows): + design.design.__init__(self, name) self.rows = rows @@ -53,13 +52,14 @@ class wordline_driver(design.design): # This is just used for measurements, # so don't add the module - self.inv = pinv() + self.inv = factory.create(module_type="pinv") self.add_mod(self.inv) - self.inv_no_output = pinv(route_output=False) + self.inv_no_output = factory.create(module_type="pinv", + route_output=False) self.add_mod(self.inv_no_output) - self.nand2 = pnand2() + self.nand2 = factory.create(module_type="pnand2") self.add_mod(self.nand2) @@ -237,4 +237,4 @@ class wordline_driver(design.design): """Get the relative capacitance of all the enable connections in the bank""" #The enable is connected to a nand2 for every row. total_cin = self.nand2.get_cin() * self.rows - return total_cin \ No newline at end of file + return total_cin diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index 3b5e75d9..4bcfbcb0 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -2,6 +2,7 @@ from math import log import design from tech import drc import debug +from sram_factory import factory from vector import vector from globals import OPTS @@ -11,8 +12,8 @@ class write_driver_array(design.design): Dynamically generated write driver array of all bitlines. """ - def __init__(self, columns, word_size): - design.design.__init__(self, "write_driver_array") + def __init__(self, name, columns, word_size): + design.design.__init__(self, name) debug.info(1, "Creating {0}".format(self.name)) self.columns = columns @@ -53,17 +54,12 @@ class write_driver_array(design.design): self.add_pin("gnd") def add_modules(self): - from importlib import reload - c = reload(__import__(OPTS.write_driver)) - self.mod_write_driver = getattr(c, OPTS.write_driver) - self.driver = self.mod_write_driver("write_driver") + self.driver = factory.create(module_type="write_driver") self.add_mod(self.driver) # This is just used for measurements, # so don't add the module - c = reload(__import__(OPTS.bitcell)) - self.mod_bitcell = getattr(c, OPTS.bitcell) - self.bitcell = self.mod_bitcell() + self.bitcell = factory.create(module_type="bitcell") def create_write_array(self): self.driver_insts = {} diff --git a/compiler/options.py b/compiler/options.py index bd4bf607..d1a9d7d8 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -72,23 +72,23 @@ class options(optparse.Values): num_banks = 1 # These are the default modules that can be over-riden + bank_select = "bank_select" + bitcell_array = "bitcell_array" + bitcell = "bitcell" + column_mux_array = "single_level_column_mux_array" + control_logic = "control_logic" decoder = "hierarchical_decoder" + delay_chain = "delay_chain" dff_array = "dff_array" dff = "dff" - control_logic = "control_logic" - bitcell_array = "bitcell_array" - sense_amp = "sense_amp" - sense_amp_array = "sense_amp_array" precharge_array = "precharge_array" - column_mux_array = "single_level_column_mux_array" - write_driver = "write_driver" - write_driver_array = "write_driver_array" - tri_gate = "tri_gate" - tri_gate_array = "tri_gate_array" - wordline_driver = "wordline_driver" - replica_bitline = "replica_bitline" replica_bitcell = "replica_bitcell" - bitcell = "bitcell" - delay_chain = "delay_chain" - bank_select = "bank_select" + replica_bitline = "replica_bitline" + sense_amp_array = "sense_amp_array" + sense_amp = "sense_amp" + tri_gate_array = "tri_gate_array" + tri_gate = "tri_gate" + wordline_driver = "wordline_driver" + write_driver_array = "write_driver_array" + write_driver = "write_driver" diff --git a/compiler/pgates/pand2.py b/compiler/pgates/pand2.py index 5eb1ceb9..0e1acde6 100644 --- a/compiler/pgates/pand2.py +++ b/compiler/pgates/pand2.py @@ -3,28 +3,16 @@ from tech import drc from math import log from vector import vector from globals import OPTS -from pnand2 import pnand2 -from pinv import pinv import pgate +from sram_factory import factory class pand2(pgate.pgate): """ This is a simple buffer used for driving loads. """ - from importlib import reload - c = reload(__import__(OPTS.bitcell)) - bitcell = getattr(c, OPTS.bitcell) - - unique_id = 1 - - def __init__(self, size=1, height=None, name=""): - + def __init__(self, name, size=1, height=None): self.size = size - if name=="": - name = "pand2_{0}_{1}".format(size, pand2.unique_id) - pand2.unique_id += 1 - pgate.pgate.__init__(self, name, height) debug.info(1, "Creating {}".format(self.name)) @@ -41,10 +29,10 @@ class pand2(pgate.pgate): def create_modules(self): # Shield the cap, but have at least a stage effort of 4 - self.nand = pnand2(height=self.height) + self.nand = factory.create(module_type="pnand2",height=self.height) self.add_mod(self.nand) - self.inv = pinv(size=self.size, height=self.height) + self.inv = factory.create(module_type="pinv", size=self.size, height=self.height) self.add_mod(self.inv) def create_layout(self): diff --git a/compiler/pgates/pbuf.py b/compiler/pgates/pbuf.py index 9b6c59ff..a86aea1c 100644 --- a/compiler/pgates/pbuf.py +++ b/compiler/pgates/pbuf.py @@ -3,29 +3,19 @@ from tech import drc from math import log from vector import vector from globals import OPTS -from pinv import pinv import pgate +from sram_factory import factory class pbuf(pgate.pgate): """ This is a simple buffer used for driving loads. """ - from importlib import reload - c = reload(__import__(OPTS.bitcell)) - bitcell = getattr(c, OPTS.bitcell) - - unique_id = 1 - - def __init__(self, size=4, height=None, name=""): - + def __init__(self, name, size=4, height=None): + self.stage_effort = 4 self.size = size self.height = height - if name=="": - name = "pbuf_{0}_{1}".format(self.size, pbuf.unique_id) - pbuf.unique_id += 1 - pgate.pgate.__init__(self, name, height) debug.info(1, "creating {0} with size of {1}".format(self.name,self.size)) @@ -54,10 +44,10 @@ class pbuf(pgate.pgate): def create_modules(self): # Shield the cap, but have at least a stage effort of 4 input_size = max(1,int(self.size/self.stage_effort)) - self.inv1 = pinv(size=input_size, height=self.height) + self.inv1 = factory.create(module_type="pinv", size=input_size, height=self.height) self.add_mod(self.inv1) - self.inv2 = pinv(size=self.size, height=self.height) + self.inv2 = factory.create(module_type="pinv", size=self.size, height=self.height) self.add_mod(self.inv2) def create_insts(self): @@ -141,4 +131,4 @@ class pbuf(pgate.pgate): def get_cin(self): """Returns the relative capacitance of the input""" input_cin = self.inv1.get_cin() - return input_cin \ No newline at end of file + return input_cin diff --git a/compiler/pgates/pdriver.py b/compiler/pgates/pdriver.py index 5da68032..934412d6 100644 --- a/compiler/pgates/pdriver.py +++ b/compiler/pgates/pdriver.py @@ -5,15 +5,13 @@ from tech import drc from math import log from vector import vector from globals import OPTS -from pinv import pinv +from sram_factory import factory class pdriver(pgate.pgate): """ This instantiates an even or odd number of inverters sized for driving a load. """ - unique_id = 1 - - def __init__(self, neg_polarity=False, fanout_size=8, size_list = [], height=None, name=""): + def __init__(self, name, neg_polarity=False, fanout_size=8, size_list = [], height=None): self.stage_effort = 4 self.height = height @@ -24,10 +22,6 @@ class pdriver(pgate.pgate): if len(self.size_list) > 0 and (self.fanout_size != 8 or self.neg_polarity): debug.error("Cannot specify both size_list and neg_polarity or fanout_size.", -1) - if name=="": - name = "pdriver_{}".format(pdriver.unique_id) - pdriver.unique_id += 1 - pgate.pgate.__init__(self, name, height) debug.info(1, "Creating {}".format(self.name)) @@ -123,11 +117,13 @@ class pdriver(pgate.pgate): self.inv_list = [] if len(self.size_list) > 0: # size list specified for x in range(len(self.size_list)): - self.inv_list.append(pinv(size=self.size_list[x], height=self.height)) + temp_inv = factory.create(module_type="pinv", size=self.size_list[x], height=self.height) + self.inv_list.append(temp_inv) self.add_mod(self.inv_list[x]) else: # find inv sizes for x in range(len(self.calc_size_list)): - self.inv_list.append(pinv(size=self.calc_size_list[x], height=self.height)) + temp_inv = factory.create(module_type="pinv", size=self.calc_size_list[x], height=self.height) + self.inv_list.append(temp_inv) self.add_mod(self.inv_list[x]) diff --git a/compiler/pgates/pgate.py b/compiler/pgates/pgate.py index fc839270..b9889601 100644 --- a/compiler/pgates/pgate.py +++ b/compiler/pgates/pgate.py @@ -5,6 +5,7 @@ from tech import drc, parameter, spice from ptx import ptx from vector import vector from globals import OPTS +from sram_factory import factory class pgate(design.design): """ @@ -18,10 +19,7 @@ class pgate(design.design): if height: self.height = height elif not height: - from importlib import reload - c = reload(__import__(OPTS.bitcell)) - bitcell = getattr(c, OPTS.bitcell) - b = bitcell() + b = factory.create(module_type="bitcell") self.height = b.height diff --git a/compiler/pgates/pinv.py b/compiler/pgates/pinv.py index 31682360..daaa28f6 100644 --- a/compiler/pgates/pinv.py +++ b/compiler/pgates/pinv.py @@ -19,15 +19,11 @@ class pinv(pgate.pgate): output to the right side of the cell for easier access. """ - unique_id = 1 - - def __init__(self, size=1, beta=parameter["beta"], height=None, route_output=True): + def __init__(self, name, size=1, beta=parameter["beta"], height=None, route_output=True): # We need to keep unique names because outputting to GDSII # will use the last record with a given name. I.e., you will # over-write a design in GDS if one has and the other doesn't # have poly connected, for example. - name = "pinv_{}".format(pinv.unique_id) - pinv.unique_id += 1 pgate.pgate.__init__(self, name, height) debug.info(2, "create pinv structure {0} with size of {1}".format(name, size)) diff --git a/compiler/pgates/pinvbuf.py b/compiler/pgates/pinvbuf.py index 13c376cf..adce2d6c 100644 --- a/compiler/pgates/pinvbuf.py +++ b/compiler/pgates/pinvbuf.py @@ -4,16 +4,14 @@ from tech import drc from math import log from vector import vector from globals import OPTS -from pinv import pinv +from sram_factory import factory class pinvbuf(design.design): """ This is a simple inverter/buffer used for driving loads. It is used in the column decoder for 1:2 decoding and as the clock buffer. """ - unique_id = 1 - - def __init__(self, driver_size=4, height=None, name=""): + def __init__(self, name, size=4, height=None): self.stage_effort = 4 self.row_height = height @@ -22,11 +20,8 @@ class pinvbuf(design.design): # stage effort of 4 or less # The pinvbuf has a FO of 2 for the first stage, so the second stage # should be sized "half" to prevent loading of the first stage - self.driver_size = driver_size - self.predriver_size = max(int(self.driver_size/(self.stage_effort/2)),1) - if name=="": - name = "pinvbuf_{0}_{1}_{2}".format(self.predriver_size, self.driver_size, pinvbuf.unique_id) - pinvbuf.unique_id += 1 + self.size = size + self.predriver_size = max(int(self.size/(self.stage_effort/2)),1) design.design.__init__(self, name) debug.info(1, "Creating {}".format(self.name)) @@ -65,13 +60,13 @@ class pinvbuf(design.design): # Shield the cap, but have at least a stage effort of 4 input_size = max(1,int(self.predriver_size/self.stage_effort)) - self.inv = pinv(size=input_size, height=self.row_height) + self.inv = factory.create(module_type="pinv", size=input_size, height=self.row_height) self.add_mod(self.inv) - self.inv1 = pinv(size=self.predriver_size, height=self.row_height) + self.inv1 = factory.create(module_type="pinv", size=self.predriver_size, height=self.row_height) self.add_mod(self.inv1) - self.inv2 = pinv(size=self.driver_size, height=self.row_height) + self.inv2 = factory.create(module_type="pinv", size=self.size, height=self.row_height) self.add_mod(self.inv2) def create_insts(self): @@ -217,4 +212,4 @@ class pinvbuf(design.design): stage3 = self.inv2.get_effort_stage(external_cout, last_stage_is_rise) stage_effort_list.append(stage3) - return stage_effort_list \ No newline at end of file + return stage_effort_list diff --git a/compiler/pgates/pnand2.py b/compiler/pgates/pnand2.py index e767b87e..e1e8188b 100644 --- a/compiler/pgates/pnand2.py +++ b/compiler/pgates/pnand2.py @@ -12,13 +12,8 @@ class pnand2(pgate.pgate): This module generates gds of a parametrically sized 2-input nand. This model use ptx to generate a 2-input nand within a cetrain height. """ - - unique_id = 1 - - def __init__(self, size=1, height=None): + def __init__(self, name, size=1, height=None): """ Creates a cell for a simple 2 input nand """ - name = "pnand2_{0}".format(pnand2.unique_id) - pnand2.unique_id += 1 pgate.pgate.__init__(self, name, height) debug.info(2, "create pnand2 structure {0} with size of {1}".format(name, size)) @@ -260,4 +255,4 @@ class pnand2(pgate.pgate): Optional is_rise refers to the input direction rise/fall. Input inverted by this stage. """ parasitic_delay = 2 - return logical_effort.logical_effort(self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise) \ No newline at end of file + return logical_effort.logical_effort(self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise) diff --git a/compiler/pgates/pnand3.py b/compiler/pgates/pnand3.py index 4dab5264..16902826 100644 --- a/compiler/pgates/pnand3.py +++ b/compiler/pgates/pnand3.py @@ -11,13 +11,8 @@ class pnand3(pgate.pgate): This module generates gds of a parametrically sized 2-input nand. This model use ptx to generate a 2-input nand within a cetrain height. """ - - unique_id = 1 - - def __init__(self, size=1, height=None): + def __init__(self, name, size=1, height=None): """ Creates a cell for a simple 3 input nand """ - name = "pnand3_{0}".format(pnand3.unique_id) - pnand3.unique_id += 1 pgate.pgate.__init__(self, name, height) debug.info(2, "create pnand3 structure {0} with size of {1}".format(name, size)) @@ -272,4 +267,4 @@ class pnand3(pgate.pgate): Optional is_rise refers to the input direction rise/fall. Input inverted by this stage. """ parasitic_delay = 3 - return logical_effort.logical_effort(self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise) \ No newline at end of file + return logical_effort.logical_effort(self.size, self.get_cin(), cout, parasitic_delay, not inp_is_rise) diff --git a/compiler/pgates/pnor2.py b/compiler/pgates/pnor2.py index 65aaf7f8..21ba14ce 100644 --- a/compiler/pgates/pnor2.py +++ b/compiler/pgates/pnor2.py @@ -11,13 +11,8 @@ class pnor2(pgate.pgate): This module generates gds of a parametrically sized 2-input nor. This model use ptx to generate a 2-input nor within a cetrain height. """ - - unique_id = 1 - - def __init__(self, size=1, height=None): + def __init__(self, name, size=1, height=None): """ Creates a cell for a simple 2 input nor """ - name = "pnor2_{0}".format(pnor2.unique_id) - pnor2.unique_id += 1 pgate.pgate.__init__(self, name, height) debug.info(2, "create pnor2 structure {0} with size of {1}".format(name, size)) diff --git a/compiler/pgates/precharge.py b/compiler/pgates/precharge.py index a1422cb2..64ff98a1 100644 --- a/compiler/pgates/precharge.py +++ b/compiler/pgates/precharge.py @@ -5,25 +5,18 @@ from tech import drc, parameter from ptx import ptx from vector import vector from globals import OPTS +from sram_factory import factory class precharge(pgate.pgate): """ Creates a single precharge cell This module implements the precharge bitline cell used in the design. """ - - unique_id = 1 - def __init__(self, name, size=1, bitcell_bl="bl", bitcell_br="br"): - name = name+"_{}".format(precharge.unique_id) - precharge.unique_id += 1 pgate.pgate.__init__(self, name) debug.info(2, "create single precharge cell: {0}".format(name)) - from importlib import reload - c = reload(__import__(OPTS.bitcell)) - self.mod_bitcell = getattr(c, OPTS.bitcell) - self.bitcell = self.mod_bitcell() + self.bitcell = factory.create(module_type="bitcell") self.beta = parameter["beta"] self.ptx_width = self.beta*parameter["min_tx_size"] @@ -268,4 +261,4 @@ class precharge(pgate.pgate): #The enable connect to three pmos gates. They all use the same size pmos. pmos_cin = self.pmos.get_cin() return 3*pmos_cin - \ No newline at end of file + diff --git a/compiler/pgates/ptx.py b/compiler/pgates/ptx.py index 82c79aed..6c81aaee 100644 --- a/compiler/pgates/ptx.py +++ b/compiler/pgates/ptx.py @@ -15,7 +15,7 @@ class ptx(design.design): you to connect the fingered gates and active for parallel devices. """ - def __init__(self, width=drc("minwidth_tx"), mults=1, tx_type="nmos", connect_active=False, connect_poly=False, num_contacts=None): + def __init__(self, name="", width=drc("minwidth_tx"), mults=1, tx_type="nmos", connect_active=False, connect_poly=False, num_contacts=None): # We need to keep unique names because outputting to GDSII # will use the last record with a given name. I.e., you will # over-write a design in GDS if one has and the other doesn't @@ -355,4 +355,4 @@ class ptx(design.design): def get_cin(self): """Returns the relative gate cin of the tx""" - return self.tx_width/drc("minwidth_tx") \ No newline at end of file + return self.tx_width/drc("minwidth_tx") diff --git a/compiler/pgates/single_level_column_mux.py b/compiler/pgates/single_level_column_mux.py index 197164f3..4b5db508 100644 --- a/compiler/pgates/single_level_column_mux.py +++ b/compiler/pgates/single_level_column_mux.py @@ -5,6 +5,7 @@ from vector import vector import contact from ptx import ptx from globals import OPTS +from sram_factory import factory class single_level_column_mux(design.design): """ @@ -13,14 +14,10 @@ class single_level_column_mux(design.design): to minimum size. Default is 8x. Per Samira and Hodges-Jackson book: Column-mux transistors driven by the decoder must be sized for optimal speed """ + def __init__(self, name, tx_size=8, bitcell_bl="bl", bitcell_br="br"): - # This is needed for different bitline spacings - unique_id = 1 - - def __init__(self, tx_size=8, bitcell_bl="bl", bitcell_br="br"): self.tx_size = int(tx_size) - name="single_level_column_mux_{}_{}".format(self.tx_size,single_level_column_mux.unique_id) - single_level_column_mux.unique_id += 1 + design.design.__init__(self, name) debug.info(2, "create single column mux cell: {0}".format(name)) @@ -47,12 +44,7 @@ class single_level_column_mux(design.design): self.add_wells() def add_modules(self): - # This is just used for measurements, - # so don't add the module - from importlib import reload - c = reload(__import__(OPTS.bitcell)) - self.mod_bitcell = getattr(c, OPTS.bitcell) - self.bitcell = self.mod_bitcell() + self.bitcell = factory.create(module_type="bitcell") # Adds nmos_lower,nmos_upper to the module self.ptx_width = self.tx_size*drc("minwidth_tx") diff --git a/compiler/sram_base.py b/compiler/sram_base.py index b51ebae9..39f139c6 100644 --- a/compiler/sram_base.py +++ b/compiler/sram_base.py @@ -10,6 +10,7 @@ import logical_effort from design import design from verilog import verilog from lef import lef +from sram_factory import factory class sram_base(design, verilog, lef): """ @@ -239,10 +240,7 @@ class sram_base(design, verilog, lef): def add_modules(self): - """ Create all the modules that will be used """ - c = reload(__import__(OPTS.bitcell)) - self.mod_bitcell = getattr(c, OPTS.bitcell) - self.bitcell = self.mod_bitcell() + self.bitcell = factory.create(module_type=OPTS.bitcell) # Create the address and control flops (but not the clk) from dff_array import dff_array diff --git a/compiler/sram_config.py b/compiler/sram_config.py index e4f94b4a..24e3cbc9 100644 --- a/compiler/sram_config.py +++ b/compiler/sram_config.py @@ -2,6 +2,7 @@ import debug from math import log,sqrt,ceil from importlib import reload from globals import OPTS +from sram_factory import factory class sram_config: """ This is a structure that is used to hold the SRAM configuration options. """ @@ -29,10 +30,7 @@ class sram_config: def compute_sizes(self): """ Computes the organization of the memory using bitcell size by trying to make it square.""" - c = reload(__import__(OPTS.bitcell)) - self.mod_bitcell = getattr(c, OPTS.bitcell) - # pass a copy of myself for the port numbers - self.bitcell = self.mod_bitcell() + self.bitcell = factory.create(module_type="bitcell") debug.check(self.num_banks in [1,2,4], "Valid number of banks are 1 , 2 and 4.") diff --git a/compiler/tests/04_pand2_test.py b/compiler/tests/04_pand2_test.py index 68433e96..91b3458e 100755 --- a/compiler/tests/04_pand2_test.py +++ b/compiler/tests/04_pand2_test.py @@ -21,7 +21,7 @@ class pand2_test(openram_test): import pand2 debug.info(2, "Testing pand2 gate 4x") - a = pand2.pand2(4) + a = pand2.pand2(name="pand2x4", size=4) self.local_check(a) globals.end_openram() diff --git a/compiler/tests/04_pbitcell_test.py b/compiler/tests/04_pbitcell_test.py index e5dbbc5e..9dd9341c 100755 --- a/compiler/tests/04_pbitcell_test.py +++ b/compiler/tests/04_pbitcell_test.py @@ -10,84 +10,94 @@ sys.path.append(os.path.join(sys.path[0],"..")) import globals from globals import OPTS import debug - -OPTS = globals.OPTS +from sram_factory import factory #@unittest.skip("SKIPPING 04_pbitcell_test") class pbitcell_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) + from pbitcell import pbitcell import tech OPTS.num_rw_ports=1 OPTS.num_w_ports=1 OPTS.num_r_ports=1 + factory.reset() debug.info(2, "Bitcell with 1 of each port: read/write, write, and read") - tx = pbitcell() + tx = pbitcell(name="pbc") self.local_check(tx) OPTS.num_rw_ports=0 OPTS.num_w_ports=1 OPTS.num_r_ports=1 + factory.reset() debug.info(2, "Bitcell with 0 read/write ports") - tx = pbitcell() + tx = pbitcell(name="pbc") self.local_check(tx) OPTS.num_rw_ports=1 OPTS.num_w_ports=0 OPTS.num_r_ports=1 + factory.reset() debug.info(2, "Bitcell with 0 write ports") - tx = pbitcell() + tx = pbitcell(name="pbc") self.local_check(tx) OPTS.num_rw_ports=1 OPTS.num_w_ports=1 OPTS.num_r_ports=0 + factory.reset() debug.info(2, "Bitcell with 0 read ports") - tx = pbitcell() + tx = pbitcell(name="pbc") self.local_check(tx) OPTS.num_rw_ports=1 OPTS.num_w_ports=0 OPTS.num_r_ports=0 + factory.reset() debug.info(2, "Bitcell with 0 read ports and 0 write ports") - tx = pbitcell() + tx = pbitcell(name="pbc") self.local_check(tx) OPTS.num_rw_ports=2 OPTS.num_w_ports=2 OPTS.num_r_ports=2 + factory.reset() debug.info(2, "Bitcell with 2 of each port: read/write, write, and read") - tx = pbitcell() + tx = pbitcell(name="pbc") self.local_check(tx) OPTS.num_rw_ports=0 OPTS.num_w_ports=2 OPTS.num_r_ports=2 + factory.reset() debug.info(2, "Bitcell with 0 read/write ports") - tx = pbitcell() + tx = pbitcell(name="pbc") self.local_check(tx) OPTS.num_rw_ports=2 OPTS.num_w_ports=0 OPTS.num_r_ports=2 + factory.reset() debug.info(2, "Bitcell with 0 write ports") - tx = pbitcell() + tx = pbitcell(name="pbc") self.local_check(tx) OPTS.num_rw_ports=2 OPTS.num_w_ports=2 OPTS.num_r_ports=0 + factory.reset() debug.info(2, "Bitcell with 0 read ports") - tx = pbitcell() + tx = pbitcell(name="pbc") self.local_check(tx) OPTS.num_rw_ports=2 OPTS.num_w_ports=0 OPTS.num_r_ports=0 + factory.reset() debug.info(2, "Bitcell with 0 read ports and 0 write ports") - tx = pbitcell() + tx = pbitcell(name="pbc") self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/04_pbuf_test.py b/compiler/tests/04_pbuf_test.py index f784c671..ed5b8627 100755 --- a/compiler/tests/04_pbuf_test.py +++ b/compiler/tests/04_pbuf_test.py @@ -21,7 +21,7 @@ class pbuf_test(openram_test): import pbuf debug.info(2, "Testing inverter/buffer 4x 8x") - a = pbuf.pbuf(8) + a = pbuf.pbuf(name="pbufx8", size=8) self.local_check(a) globals.end_openram() diff --git a/compiler/tests/04_pdriver_test.py b/compiler/tests/04_pdriver_test.py index 8db39d8c..ee1b8e1a 100755 --- a/compiler/tests/04_pdriver_test.py +++ b/compiler/tests/04_pdriver_test.py @@ -23,16 +23,21 @@ class pdriver_test(openram_test): debug.info(2, "Testing inverter/buffer 4x 8x") # a tests the error message for specifying conflicting conditions #a = pdriver.pdriver(fanout_size = 4,size_list = [1,2,4,8]) - b = pdriver.pdriver(size_list = [1,2,4,8]) - c = pdriver.pdriver(fanout_size = 50) - d = pdriver.pdriver(fanout_size = 50, neg_polarity = True) - e = pdriver.pdriver(fanout_size = 64) - f = pdriver.pdriver(fanout_size = 64, neg_polarity = True) #self.local_check(a) + + b = pdriver.pdriver(name="pdriver1", size_list = [1,2,4,8]) self.local_check(b) + + c = pdriver.pdriver(name="pdriver2", fanout_size = 50) self.local_check(c) + + d = pdriver.pdriver(name="pdriver3", fanout_size = 50, neg_polarity = True) self.local_check(d) + + e = pdriver.pdriver(name="pdriver4", fanout_size = 64) self.local_check(e) + + f = pdriver.pdriver(name="pdriver5", fanout_size = 64, neg_polarity = True) self.local_check(f) globals.end_openram() diff --git a/compiler/tests/04_pinv_10x_test.py b/compiler/tests/04_pinv_10x_test.py index d457d2a9..42c38ca1 100755 --- a/compiler/tests/04_pinv_10x_test.py +++ b/compiler/tests/04_pinv_10x_test.py @@ -19,7 +19,7 @@ class pinv_test(openram_test): import tech debug.info(2, "Checking 10x inverter") - tx = pinv.pinv(size=8) + tx = pinv.pinv(name="pinvx10",size=8) self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/04_pinv_1x_beta_test.py b/compiler/tests/04_pinv_1x_beta_test.py index 77ff5454..9ac66a65 100755 --- a/compiler/tests/04_pinv_1x_beta_test.py +++ b/compiler/tests/04_pinv_1x_beta_test.py @@ -19,7 +19,7 @@ class pinv_test(openram_test): import tech debug.info(2, "Checking 1x beta=3 size inverter") - tx = pinv.pinv(size=1, beta=3) + tx = pinv.pinv(name="pinvx1b", size=1, beta=3) self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/04_pinv_1x_test.py b/compiler/tests/04_pinv_1x_test.py index 49cb1cb1..850aa78e 100755 --- a/compiler/tests/04_pinv_1x_test.py +++ b/compiler/tests/04_pinv_1x_test.py @@ -18,7 +18,7 @@ class pinv_test(openram_test): import tech debug.info(2, "Checking 1x size inverter") - tx = pinv.pinv(size=1) + tx = pinv.pinv(name="pinvx1", size=1) self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/04_pinv_2x_test.py b/compiler/tests/04_pinv_2x_test.py index 84bc55ee..33950da9 100755 --- a/compiler/tests/04_pinv_2x_test.py +++ b/compiler/tests/04_pinv_2x_test.py @@ -19,7 +19,7 @@ class pinv_test(openram_test): import tech debug.info(2, "Checking 2x size inverter") - tx = pinv.pinv(size=2) + tx = pinv.pinv(name="pinvx2", size=2) self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/04_pinvbuf_test.py b/compiler/tests/04_pinvbuf_test.py index d35f1ec7..53814628 100755 --- a/compiler/tests/04_pinvbuf_test.py +++ b/compiler/tests/04_pinvbuf_test.py @@ -18,7 +18,7 @@ class pinvbuf_test(openram_test): import pinvbuf debug.info(2, "Testing inverter/buffer 4x 8x") - a = pinvbuf.pinvbuf(8) + a = pinvbuf.pinvbuf(name="pinvufx8", size=8) self.local_check(a) globals.end_openram() diff --git a/compiler/tests/04_pnand2_test.py b/compiler/tests/04_pnand2_test.py index a2ac9288..cb0b65c6 100755 --- a/compiler/tests/04_pnand2_test.py +++ b/compiler/tests/04_pnand2_test.py @@ -21,7 +21,7 @@ class pnand2_test(openram_test): import tech debug.info(2, "Checking 2-input nand gate") - tx = pnand2.pnand2(size=1) + tx = pnand2.pnand2(name="pnand2", size=1) self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/04_pnand3_test.py b/compiler/tests/04_pnand3_test.py index f6daedda..f3bbdb73 100755 --- a/compiler/tests/04_pnand3_test.py +++ b/compiler/tests/04_pnand3_test.py @@ -21,7 +21,7 @@ class pnand3_test(openram_test): import tech debug.info(2, "Checking 3-input nand gate") - tx = pnand3.pnand3(size=1) + tx = pnand3.pnand3(name="pnand3", size=1) self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/04_pnor2_test.py b/compiler/tests/04_pnor2_test.py index ce4b19ae..32214ded 100755 --- a/compiler/tests/04_pnor2_test.py +++ b/compiler/tests/04_pnor2_test.py @@ -21,7 +21,7 @@ class pnor2_test(openram_test): import tech debug.info(2, "Checking 2-input nor gate") - tx = pnor2.pnor2(size=1) + tx = pnor2.pnor2(name="pnor2", size=1) self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/04_precharge_test.py b/compiler/tests/04_precharge_test.py index 6c0cfe56..a73595eb 100755 --- a/compiler/tests/04_precharge_test.py +++ b/compiler/tests/04_precharge_test.py @@ -10,6 +10,7 @@ sys.path.append(os.path.join(sys.path[0],"..")) import globals from globals import OPTS import debug +from sram_factory import factory class precharge_test(openram_test): @@ -28,7 +29,8 @@ class precharge_test(openram_test): OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 OPTS.num_w_ports = 1 - + + factory.reset() debug.info(2, "Checking precharge for pbitcell (innermost connections)") tx = precharge.precharge(name="precharge_driver", size=1, bitcell_bl="bl0", bitcell_br="br0") self.local_check(tx) diff --git a/compiler/tests/04_replica_pbitcell_test.py b/compiler/tests/04_replica_pbitcell_test.py index ce9f00b9..9a672419 100755 --- a/compiler/tests/04_replica_pbitcell_test.py +++ b/compiler/tests/04_replica_pbitcell_test.py @@ -10,29 +10,31 @@ sys.path.append(os.path.join(sys.path[0],"..")) import globals from globals import OPTS import debug +from sram_factory import factory class replica_pbitcell_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) import replica_pbitcell - import tech OPTS.bitcell = "pbitcell" OPTS.num_rw_ports = 1 OPTS.num_r_ports = 0 OPTS.num_w_ports = 0 - + + factory.reset() debug.info(2, "Checking replica bitcell using pbitcell (small cell)") - tx = replica_pbitcell.replica_pbitcell() + tx = replica_pbitcell.replica_pbitcell(name="rpbc") self.local_check(tx) OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 OPTS.num_w_ports = 1 - + + factory.reset() debug.info(2, "Checking replica bitcell using pbitcell (large cell)") - tx = replica_pbitcell.replica_pbitcell() + tx = replica_pbitcell.replica_pbitcell(name="rpbc") self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/04_single_level_column_mux_test.py b/compiler/tests/04_single_level_column_mux_test.py index c43b15fd..2a107b9a 100755 --- a/compiler/tests/04_single_level_column_mux_test.py +++ b/compiler/tests/04_single_level_column_mux_test.py @@ -10,6 +10,7 @@ sys.path.append(os.path.join(sys.path[0],"..")) import globals from globals import OPTS import debug +from sram_factory import factory #@unittest.skip("SKIPPING 04_driver_test") @@ -22,7 +23,7 @@ class single_level_column_mux_test(openram_test): # check single level column mux in single port debug.info(2, "Checking column mux") - tx = single_level_column_mux.single_level_column_mux(tx_size=8) + tx = single_level_column_mux.single_level_column_mux(name="mux8", tx_size=8) self.local_check(tx) # check single level column mux in multi-port @@ -30,13 +31,15 @@ class single_level_column_mux_test(openram_test): OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 OPTS.num_w_ports = 1 - + + factory.reset() debug.info(2, "Checking column mux for pbitcell (innermost connections)") - tx = single_level_column_mux.single_level_column_mux(tx_size=8, bitcell_bl="bl0", bitcell_br="br0") + tx = single_level_column_mux.single_level_column_mux(name="mux8_2", tx_size=8, bitcell_bl="bl0", bitcell_br="br0") self.local_check(tx) + factory.reset() debug.info(2, "Checking column mux for pbitcell (outermost connections)") - tx = single_level_column_mux.single_level_column_mux(tx_size=8, bitcell_bl="bl2", bitcell_br="br2") + tx = single_level_column_mux.single_level_column_mux(name="mux8_3", tx_size=8, bitcell_bl="bl2", bitcell_br="br2") self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/06_hierarchical_decoder_test.py b/compiler/tests/06_hierarchical_decoder_test.py index 09201149..2400d3c2 100755 --- a/compiler/tests/06_hierarchical_decoder_test.py +++ b/compiler/tests/06_hierarchical_decoder_test.py @@ -10,6 +10,7 @@ sys.path.append(os.path.join(sys.path[0],"..")) import globals from globals import OPTS import debug +from sram_factory import factory class hierarchical_decoder_test(openram_test): @@ -20,29 +21,29 @@ class hierarchical_decoder_test(openram_test): # Doesn't require hierarchical decoder # debug.info(1, "Testing 4 row sample for hierarchical_decoder") - # a = hierarchical_decoder.hierarchical_decoder(rows=4) + # a = hierarchical_decoder.hierarchical_decoder(name="hd1, rows=4) # self.local_check(a) # Doesn't require hierarchical decoder # debug.info(1, "Testing 8 row sample for hierarchical_decoder") - # a = hierarchical_decoder.hierarchical_decoder(rows=8) + # a = hierarchical_decoder.hierarchical_decoder(name="hd2", rows=8) # self.local_check(a) # check hierarchical decoder for single port debug.info(1, "Testing 16 row sample for hierarchical_decoder") - a = hierarchical_decoder.hierarchical_decoder(rows=16) + a = hierarchical_decoder.hierarchical_decoder(name="hd3", rows=16) self.local_check(a) debug.info(1, "Testing 32 row sample for hierarchical_decoder") - a = hierarchical_decoder.hierarchical_decoder(rows=32) + a = hierarchical_decoder.hierarchical_decoder(name="hd4", rows=32) self.local_check(a) debug.info(1, "Testing 128 row sample for hierarchical_decoder") - a = hierarchical_decoder.hierarchical_decoder(rows=128) + a = hierarchical_decoder.hierarchical_decoder(name="hd5", rows=128) self.local_check(a) debug.info(1, "Testing 512 row sample for hierarchical_decoder") - a = hierarchical_decoder.hierarchical_decoder(rows=512) + a = hierarchical_decoder.hierarchical_decoder(name="hd6", rows=512) self.local_check(a) # check hierarchical decoder for multi-port @@ -50,21 +51,22 @@ class hierarchical_decoder_test(openram_test): OPTS.num_rw_ports = 1 OPTS.num_w_ports = 0 OPTS.num_r_ports = 0 - + + factory.reset() debug.info(1, "Testing 16 row sample for hierarchical_decoder (multi-port case)") - a = hierarchical_decoder.hierarchical_decoder(rows=16) + a = hierarchical_decoder.hierarchical_decoder(name="hd7", rows=16) self.local_check(a) debug.info(1, "Testing 32 row sample for hierarchical_decoder (multi-port case)") - a = hierarchical_decoder.hierarchical_decoder(rows=32) + a = hierarchical_decoder.hierarchical_decoder(name="hd8", rows=32) self.local_check(a) debug.info(1, "Testing 128 row sample for hierarchical_decoder (multi-port case)") - a = hierarchical_decoder.hierarchical_decoder(rows=128) + a = hierarchical_decoder.hierarchical_decoder(name="hd9", rows=128) self.local_check(a) debug.info(1, "Testing 512 row sample for hierarchical_decoder (multi-port case)") - a = hierarchical_decoder.hierarchical_decoder(rows=512) + a = hierarchical_decoder.hierarchical_decoder(name="hd10", rows=512) self.local_check(a) globals.end_openram() diff --git a/compiler/tests/06_hierarchical_predecode2x4_test.py b/compiler/tests/06_hierarchical_predecode2x4_test.py index e16916d6..6fbba350 100755 --- a/compiler/tests/06_hierarchical_predecode2x4_test.py +++ b/compiler/tests/06_hierarchical_predecode2x4_test.py @@ -20,7 +20,7 @@ class hierarchical_predecode2x4_test(openram_test): # checking hierarchical precode 2x4 for single port debug.info(1, "Testing sample for hierarchy_predecode2x4") - a = pre.hierarchical_predecode2x4() + a = pre.hierarchical_predecode2x4(name="pre1") self.local_check(a) # checking hierarchical precode 2x4 for multi-port @@ -30,7 +30,7 @@ class hierarchical_predecode2x4_test(openram_test): OPTS.num_r_ports = 0 debug.info(1, "Testing sample for hierarchy_predecode2x4 (multi-port case)") - a = pre.hierarchical_predecode2x4() + a = pre.hierarchical_predecode2x4(name="pre2") self.local_check(a) globals.end_openram() diff --git a/compiler/tests/06_hierarchical_predecode3x8_test.py b/compiler/tests/06_hierarchical_predecode3x8_test.py index ed5da57c..b704a50d 100755 --- a/compiler/tests/06_hierarchical_predecode3x8_test.py +++ b/compiler/tests/06_hierarchical_predecode3x8_test.py @@ -20,7 +20,7 @@ class hierarchical_predecode3x8_test(openram_test): # checking hierarchical precode 3x8 for single port debug.info(1, "Testing sample for hierarchy_predecode3x8") - a = pre.hierarchical_predecode3x8() + a = pre.hierarchical_predecode3x8(name="pre1") self.local_check(a) # checking hierarchical precode 3x8 for multi-port @@ -30,7 +30,7 @@ class hierarchical_predecode3x8_test(openram_test): OPTS.num_r_ports = 0 debug.info(1, "Testing sample for hierarchy_predecode3x8 (multi-port case)") - a = pre.hierarchical_predecode3x8() + a = pre.hierarchical_predecode3x8(name="pre2") self.local_check(a) globals.end_openram() diff --git a/compiler/tests/07_single_level_column_mux_array_test.py b/compiler/tests/07_single_level_column_mux_array_test.py index 800292b6..8cc16f56 100755 --- a/compiler/tests/07_single_level_column_mux_array_test.py +++ b/compiler/tests/07_single_level_column_mux_array_test.py @@ -9,6 +9,7 @@ sys.path.append(os.path.join(sys.path[0],"..")) import globals from globals import OPTS import debug +from sram_factory import factory class single_level_column_mux_test(openram_test): @@ -18,15 +19,15 @@ class single_level_column_mux_test(openram_test): # check single level column mux array in single port debug.info(1, "Testing sample for 2-way column_mux_array") - a = single_level_column_mux_array.single_level_column_mux_array(columns=16, word_size=8) + a = single_level_column_mux_array.single_level_column_mux_array(name="mux1", columns=16, word_size=8) self.local_check(a) debug.info(1, "Testing sample for 4-way column_mux_array") - a = single_level_column_mux_array.single_level_column_mux_array(columns=16, word_size=4) + a = single_level_column_mux_array.single_level_column_mux_array(name="mux2", columns=16, word_size=4) self.local_check(a) debug.info(1, "Testing sample for 8-way column_mux_array") - a = single_level_column_mux_array.single_level_column_mux_array(columns=32, word_size=4) + a = single_level_column_mux_array.single_level_column_mux_array(name="mux3", columns=32, word_size=4) self.local_check(a) # check single level column mux array in multi-port @@ -34,21 +35,22 @@ class single_level_column_mux_test(openram_test): OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 OPTS.num_w_ports = 1 - + + factory.reset() debug.info(1, "Testing sample for 2-way column_mux_array in multi-port") - a = single_level_column_mux_array.single_level_column_mux_array(columns=16, word_size=8, bitcell_bl="bl0", bitcell_br="br0") + a = single_level_column_mux_array.single_level_column_mux_array(name="mux4", columns=16, word_size=8, bitcell_bl="bl0", bitcell_br="br0") self.local_check(a) debug.info(1, "Testing sample for 4-way column_mux_array in multi-port") - a = single_level_column_mux_array.single_level_column_mux_array(columns=16, word_size=4, bitcell_bl="bl0", bitcell_br="br0") + a = single_level_column_mux_array.single_level_column_mux_array(name="mux5", columns=16, word_size=4, bitcell_bl="bl0", bitcell_br="br0") self.local_check(a) debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (innermost connections)") - a = single_level_column_mux_array.single_level_column_mux_array(columns=32, word_size=4, bitcell_bl="bl0", bitcell_br="br0") + a = single_level_column_mux_array.single_level_column_mux_array(name="mux6", columns=32, word_size=4, bitcell_bl="bl0", bitcell_br="br0") self.local_check(a) debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (outermost connections)") - a = single_level_column_mux_array.single_level_column_mux_array(columns=32, word_size=4, bitcell_bl="bl2", bitcell_br="br2") + a = single_level_column_mux_array.single_level_column_mux_array(name="mux7", columns=32, word_size=4, bitcell_bl="bl2", bitcell_br="br2") self.local_check(a) globals.end_openram() diff --git a/compiler/tests/08_precharge_array_test.py b/compiler/tests/08_precharge_array_test.py index cdf6100e..c31f133a 100755 --- a/compiler/tests/08_precharge_array_test.py +++ b/compiler/tests/08_precharge_array_test.py @@ -10,17 +10,17 @@ sys.path.append(os.path.join(sys.path[0],"..")) import globals from globals import OPTS import debug +from sram_factory import factory class precharge_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) import precharge_array - import tech # check precharge array in single port debug.info(2, "Checking 3 column precharge") - pc = precharge_array.precharge_array(columns=3) + pc = precharge_array.precharge_array(name="pre1", columns=3) self.local_check(pc) # check precharge array in multi-port @@ -28,17 +28,18 @@ class precharge_test(openram_test): OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 OPTS.num_w_ports = 0 - + + factory.reset() debug.info(2, "Checking 3 column precharge array for 1RW/1R bitcell") - pc = precharge_array.precharge_array(columns=3, bitcell_bl="bl0", bitcell_br="br0") + pc = precharge_array.precharge_array(name="pre2", columns=3, bitcell_bl="bl0", bitcell_br="br0") self.local_check(pc) # debug.info(2, "Checking 3 column precharge array for pbitcell (innermost connections)") - # pc = precharge_array.precharge_array(columns=3, bitcell_bl="bl0", bitcell_br="br0") + # pc = precharge_array.precharge_array(name="pre3", columns=3, bitcell_bl="bl0", bitcell_br="br0") # self.local_check(pc) # debug.info(2, "Checking 3 column precharge array for pbitcell (outermost connections)") - # pc = precharge_array.precharge_array(columns=3, bitcell_bl="bl2", bitcell_br="br2") + # pc = precharge_array.precharge_array(name="pre4", columns=3, bitcell_bl="bl2", bitcell_br="br2") # self.local_check(pc) globals.end_openram() diff --git a/compiler/tests/08_wordline_driver_test.py b/compiler/tests/08_wordline_driver_test.py index 369b6774..bfbf54d8 100755 --- a/compiler/tests/08_wordline_driver_test.py +++ b/compiler/tests/08_wordline_driver_test.py @@ -10,6 +10,7 @@ sys.path.append(os.path.join(sys.path[0],"..")) import globals from globals import OPTS import debug +from sram_factory import factory #@unittest.skip("SKIPPING 04_driver_test") @@ -18,11 +19,10 @@ class wordline_driver_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) import wordline_driver - import tech # check wordline driver for single port debug.info(2, "Checking driver") - tx = wordline_driver.wordline_driver(rows=8) + tx = wordline_driver.wordline_driver(name="wld1", rows=8) self.local_check(tx) # check wordline driver for multi-port @@ -30,9 +30,10 @@ class wordline_driver_test(openram_test): OPTS.num_rw_ports = 1 OPTS.num_w_ports = 0 OPTS.num_r_ports = 0 - + + factory.reset() debug.info(2, "Checking driver (multi-port case)") - tx = wordline_driver.wordline_driver(rows=8) + tx = wordline_driver.wordline_driver(name="wld2", rows=8) self.local_check(tx) globals.end_openram() diff --git a/compiler/tests/09_sense_amp_array_test.py b/compiler/tests/09_sense_amp_array_test.py index a18631f9..c144b12b 100755 --- a/compiler/tests/09_sense_amp_array_test.py +++ b/compiler/tests/09_sense_amp_array_test.py @@ -10,6 +10,7 @@ sys.path.append(os.path.join(sys.path[0],"..")) import globals from globals import OPTS import debug +from sram_factory import factory class sense_amp_test(openram_test): @@ -19,11 +20,11 @@ class sense_amp_test(openram_test): # check sense amp array for single port debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2") - a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=2) + a = sense_amp_array.sense_amp_array(name="sa1", word_size=4, words_per_row=2) self.local_check(a) debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=4") - a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=4) + a = sense_amp_array.sense_amp_array(name="sa2", word_size=4, words_per_row=4) self.local_check(a) # check sense amp array for multi-port @@ -31,13 +32,14 @@ class sense_amp_test(openram_test): OPTS.num_rw_ports = 1 OPTS.num_w_ports = 0 OPTS.num_r_ports = 0 - + + factory.reset() debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2 (multi-port case)") - a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=2) + a = sense_amp_array.sense_amp_array(name="sa3", word_size=4, words_per_row=2) self.local_check(a) debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=4 (multi-port case)") - a = sense_amp_array.sense_amp_array(word_size=4, words_per_row=4) + a = sense_amp_array.sense_amp_array(name="sa4", word_size=4, words_per_row=4) self.local_check(a) globals.end_openram() diff --git a/compiler/tests/10_write_driver_array_test.py b/compiler/tests/10_write_driver_array_test.py index fa374181..98507b60 100755 --- a/compiler/tests/10_write_driver_array_test.py +++ b/compiler/tests/10_write_driver_array_test.py @@ -10,6 +10,7 @@ sys.path.append(os.path.join(sys.path[0],"..")) import globals from globals import OPTS import debug +from sram_factory import factory class write_driver_test(openram_test): @@ -19,11 +20,11 @@ class write_driver_test(openram_test): # check write driver array for single port debug.info(2, "Testing write_driver_array for columns=8, word_size=8") - a = write_driver_array.write_driver_array(columns=8, word_size=8) + a = write_driver_array.write_driver_array(name="wd1", columns=8, word_size=8) self.local_check(a) debug.info(2, "Testing write_driver_array for columns=16, word_size=8") - a = write_driver_array.write_driver_array(columns=16, word_size=8) + a = write_driver_array.write_driver_array(name="wd2", columns=16, word_size=8) self.local_check(a) # check write driver array for multi-port @@ -31,13 +32,14 @@ class write_driver_test(openram_test): OPTS.num_rw_ports = 1 OPTS.num_w_ports = 0 OPTS.num_r_ports = 0 - + + factory.reset() debug.info(2, "Testing write_driver_array for columns=8, word_size=8 (multi-port case)") - a = write_driver_array.write_driver_array(columns=8, word_size=8) + a = write_driver_array.write_driver_array(name="wd3", columns=8, word_size=8) self.local_check(a) debug.info(2, "Testing write_driver_array for columns=16, word_size=8 (multi-port case)") - a = write_driver_array.write_driver_array(columns=16, word_size=8) + a = write_driver_array.write_driver_array(name="wd4", columns=16, word_size=8) self.local_check(a) globals.end_openram() diff --git a/compiler/tests/13_delay_chain_test.py b/compiler/tests/13_delay_chain_test.py index 1052f0de..bfe2b3ff 100755 --- a/compiler/tests/13_delay_chain_test.py +++ b/compiler/tests/13_delay_chain_test.py @@ -18,7 +18,7 @@ class delay_chain_test(openram_test): import delay_chain debug.info(2, "Testing delay_chain") - a = delay_chain.delay_chain(fanout_list=[4, 4, 4, 4]) + a = delay_chain.delay_chain(name="dc", fanout_list=[4, 4, 4, 4]) self.local_check(a) globals.end_openram() diff --git a/compiler/tests/14_replica_bitline_multiport_test.py b/compiler/tests/14_replica_bitline_multiport_test.py index 41c3aa51..f379e0d2 100755 --- a/compiler/tests/14_replica_bitline_multiport_test.py +++ b/compiler/tests/14_replica_bitline_multiport_test.py @@ -10,6 +10,7 @@ sys.path.append(os.path.join(sys.path[0],"..")) import globals from globals import OPTS import debug +from sram_factory import factory class replica_bitline_multiport_test(openram_test): @@ -26,9 +27,10 @@ class replica_bitline_multiport_test(openram_test): OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 OPTS.num_w_ports = 0 - + + factory.reset() debug.info(2, "Testing 1rw 1r RBL with {0} FO4 stages, {1} rows".format(stages,rows)) - a = replica_bitline.replica_bitline(stages*[fanout],rows) + a = replica_bitline.replica_bitline(name="rbl1", delay_fanout_list=stages*[fanout], bitcell_loads=rows) self.local_check(a) # check replica bitline in pbitcell multi-port @@ -38,16 +40,18 @@ class replica_bitline_multiport_test(openram_test): OPTS.num_w_ports = 0 OPTS.num_r_ports = 0 + factory.reset() debug.info(2, "Testing RBL pbitcell 1rw with {0} FO4 stages, {1} rows".format(stages,rows)) - a = replica_bitline.replica_bitline(stages*[fanout],rows) + a = replica_bitline.replica_bitline(name="rbl2", delay_fanout_list=stages*[fanout], bitcell_loads=rows) self.local_check(a) OPTS.num_rw_ports = 1 OPTS.num_w_ports = 1 OPTS.num_r_ports = 1 + factory.reset() debug.info(2, "Testing RBL pbitcell 1rw 1w 1r with {0} FO4 stages, {1} rows".format(stages,rows)) - a = replica_bitline.replica_bitline(stages*[fanout],rows) + a = replica_bitline.replica_bitline(name="rbl3", delay_fanout_list=stages*[fanout], bitcell_loads=rows) self.local_check(a) globals.end_openram() diff --git a/compiler/tests/14_replica_bitline_test.py b/compiler/tests/14_replica_bitline_test.py index 94a49f55..ca213d5c 100755 --- a/compiler/tests/14_replica_bitline_test.py +++ b/compiler/tests/14_replica_bitline_test.py @@ -22,14 +22,14 @@ class replica_bitline_test(openram_test): fanout=4 rows=13 debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows)) - a = replica_bitline.replica_bitline(stages*[fanout],rows) + a = replica_bitline.replica_bitline(name="rbl1", delay_fanout_list=stages*[fanout], bitcell_loads=rows) self.local_check(a) #debug.error("Exiting...", 1) stages=8 rows=100 debug.info(2, "Testing RBL with {0} FO4 stages, {1} rows".format(stages,rows)) - a = replica_bitline.replica_bitline(stages*[fanout],rows) + a = replica_bitline.replica_bitline(name="rbl2", delay_fanout_list=stages*[fanout], bitcell_loads=rows) self.local_check(a) diff --git a/compiler/tests/19_psingle_bank_test.py b/compiler/tests/19_psingle_bank_test.py index ff19ac15..8e462318 100755 --- a/compiler/tests/19_psingle_bank_test.py +++ b/compiler/tests/19_psingle_bank_test.py @@ -10,15 +10,13 @@ sys.path.append(os.path.join(sys.path[0],"..")) import globals from globals import OPTS import debug +from sram_factory import factory #@unittest.skip("SKIPPING 19_psingle_bank_test") class psingle_bank_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) - global verify - import verify - from bank import bank from sram_config import sram_config OPTS.bitcell = "pbitcell" @@ -31,6 +29,7 @@ class psingle_bank_test(openram_test): num_words=16) c.words_per_row=1 + factory.reset() c.recompute_sizes() debug.info(1, "No column mux") name = "bank1_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports) @@ -39,6 +38,7 @@ class psingle_bank_test(openram_test): c.num_words=32 c.words_per_row=2 + factory.reset() c.recompute_sizes() debug.info(1, "Two way column mux") name = "bank2_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports) @@ -47,6 +47,7 @@ class psingle_bank_test(openram_test): c.num_words=64 c.words_per_row=4 + factory.reset() c.recompute_sizes() debug.info(1, "Four way column mux") name = "bank3_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports) @@ -56,6 +57,7 @@ class psingle_bank_test(openram_test): c.word_size=2 c.num_words=128 c.words_per_row=8 + factory.reset() c.recompute_sizes() debug.info(1, "Four way column mux") name = "bank4_{0}rw_{1}w_{2}r_single".format(OPTS.num_rw_ports, OPTS.num_w_ports, OPTS.num_r_ports) From 5192a01f2dfed4c8f1f425ebafe4436b6296bf6b Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 16 Jan 2019 16:30:31 -0800 Subject: [PATCH 13/44] Convert pgates to use ptx through the factory --- compiler/pgates/pgate.py | 3 +-- compiler/pgates/pinv.py | 28 ++++++++++++---------- compiler/pgates/pnand2.py | 24 ++++++++++--------- compiler/pgates/pnand3.py | 26 ++++++++++---------- compiler/pgates/pnor2.py | 24 ++++++++++--------- compiler/pgates/precharge.py | 6 ++--- compiler/pgates/single_level_column_mux.py | 3 +-- 7 files changed, 60 insertions(+), 54 deletions(-) diff --git a/compiler/pgates/pgate.py b/compiler/pgates/pgate.py index b9889601..2f641da9 100644 --- a/compiler/pgates/pgate.py +++ b/compiler/pgates/pgate.py @@ -2,7 +2,6 @@ import contact import design import debug from tech import drc, parameter, spice -from ptx import ptx from vector import vector from globals import OPTS from sram_factory import factory @@ -24,7 +23,7 @@ class pgate(design.design): def connect_pin_to_rail(self,inst,pin,supply): - """ Conencts a ptx pin to a supply rail. """ + """ Connects a ptx pin to a supply rail. """ source_pin = inst.get_pin(pin) supply_pin = self.get_pin(supply) if supply_pin.overlaps(source_pin): diff --git a/compiler/pgates/pinv.py b/compiler/pgates/pinv.py index daaa28f6..0dc1b683 100644 --- a/compiler/pgates/pinv.py +++ b/compiler/pgates/pinv.py @@ -2,12 +2,12 @@ import contact import pgate import debug from tech import drc, parameter, spice -from ptx import ptx from vector import vector from math import ceil from globals import OPTS from utils import round_to_grid import logical_effort +from sram_factory import factory class pinv(pgate.pgate): """ @@ -82,8 +82,8 @@ class pinv(pgate.pgate): # Sanity check. can we make an inverter in the height with minimum tx sizes? # Assume we need 3 metal 1 pitches (2 power rails, one between the tx for the drain) # plus the tx height - nmos = ptx(tx_type="nmos") - pmos = ptx(width=drc("minwidth_tx"), tx_type="pmos") + nmos = factory.create(module_type="ptx", tx_type="nmos") + pmos = factory.create(module_type="ptx", width=drc("minwidth_tx"), tx_type="pmos") tx_height = nmos.poly_height + pmos.poly_height # rotated m1 pitch or poly to active spacing min_channel = max(contact.poly.width + self.m1_space, @@ -143,18 +143,20 @@ class pinv(pgate.pgate): def add_ptx(self): """ Create the PMOS and NMOS transistors. """ - self.nmos = ptx(width=self.nmos_width, - mults=self.tx_mults, - tx_type="nmos", - connect_poly=True, - connect_active=True) + self.nmos = factory.create(module_type="ptx", + width=self.nmos_width, + mults=self.tx_mults, + tx_type="nmos", + connect_poly=True, + connect_active=True) self.add_mod(self.nmos) - self.pmos = ptx(width=self.pmos_width, - mults=self.tx_mults, - tx_type="pmos", - connect_poly=True, - connect_active=True) + self.pmos = factory.create(module_type="ptx", + width=self.pmos_width, + mults=self.tx_mults, + tx_type="pmos", + connect_poly=True, + connect_active=True) self.add_mod(self.pmos) def route_supply_rails(self): diff --git a/compiler/pgates/pnand2.py b/compiler/pgates/pnand2.py index e1e8188b..8ff4b953 100644 --- a/compiler/pgates/pnand2.py +++ b/compiler/pgates/pnand2.py @@ -2,10 +2,10 @@ import contact import pgate import debug from tech import drc, parameter, spice -from ptx import ptx from vector import vector from globals import OPTS import logical_effort +from sram_factory import factory class pnand2(pgate.pgate): """ @@ -56,18 +56,20 @@ class pnand2(pgate.pgate): def add_ptx(self): """ Create the PMOS and NMOS transistors. """ - self.nmos = ptx(width=self.nmos_width, - mults=self.tx_mults, - tx_type="nmos", - connect_poly=True, - connect_active=True) + self.nmos = factory.create(module_type="ptx", + width=self.nmos_width, + mults=self.tx_mults, + tx_type="nmos", + connect_poly=True, + connect_active=True) self.add_mod(self.nmos) - self.pmos = ptx(width=self.pmos_width, - mults=self.tx_mults, - tx_type="pmos", - connect_poly=True, - connect_active=True) + self.pmos = factory.create(module_type="ptx", + width=self.pmos_width, + mults=self.tx_mults, + tx_type="pmos", + connect_poly=True, + connect_active=True) self.add_mod(self.pmos) def setup_layout_constants(self): diff --git a/compiler/pgates/pnand3.py b/compiler/pgates/pnand3.py index 16902826..a4bbb1c0 100644 --- a/compiler/pgates/pnand3.py +++ b/compiler/pgates/pnand3.py @@ -2,9 +2,9 @@ import contact import pgate import debug from tech import drc, parameter, spice -from ptx import ptx from vector import vector from globals import OPTS +from sram_factory import factory class pnand3(pgate.pgate): """ @@ -56,18 +56,20 @@ class pnand3(pgate.pgate): def add_ptx(self): """ Create the PMOS and NMOS transistors. """ - self.nmos = ptx(width=self.nmos_width, - mults=self.tx_mults, - tx_type="nmos", - connect_poly=True, - connect_active=True) + self.nmos = factory.create(module_type="ptx", + width=self.nmos_width, + mults=self.tx_mults, + tx_type="nmos", + connect_poly=True, + connect_active=True) self.add_mod(self.nmos) - self.pmos = ptx(width=self.pmos_width, - mults=self.tx_mults, - tx_type="pmos", - connect_poly=True, - connect_active=True) + self.pmos = factory.create(module_type="ptx", + width=self.pmos_width, + mults=self.tx_mults, + tx_type="pmos", + connect_poly=True, + connect_active=True) self.add_mod(self.pmos) def setup_layout_constants(self): @@ -88,7 +90,7 @@ class pnand3(pgate.pgate): self.output_pos = vector(0,0.5*self.height) # This is the extra space needed to ensure DRC rules to the active contacts - nmos = ptx(tx_type="nmos") + nmos = factory.create(module_type="ptx", tx_type="nmos") extra_contact_space = max(-nmos.get_pin("D").by(),0) # This is a poly-to-poly of a flipped cell self.top_bottom_space = max(0.5*self.m1_width + self.m1_space + extra_contact_space, diff --git a/compiler/pgates/pnor2.py b/compiler/pgates/pnor2.py index 21ba14ce..b28d4cd1 100644 --- a/compiler/pgates/pnor2.py +++ b/compiler/pgates/pnor2.py @@ -2,9 +2,9 @@ import contact import pgate import debug from tech import drc, parameter, spice -from ptx import ptx from vector import vector from globals import OPTS +from sram_factory import factory class pnor2(pgate.pgate): """ @@ -53,18 +53,20 @@ class pnor2(pgate.pgate): def create_ptx(self): """ Create the PMOS and NMOS transistors. """ - self.nmos = ptx(width=self.nmos_width, - mults=self.tx_mults, - tx_type="nmos", - connect_poly=True, - connect_active=True) + self.nmos = factory.create(module_type="ptx", + width=self.nmos_width, + mults=self.tx_mults, + tx_type="nmos", + connect_poly=True, + connect_active=True) self.add_mod(self.nmos) - self.pmos = ptx(width=self.pmos_width, - mults=self.tx_mults, - tx_type="pmos", - connect_poly=True, - connect_active=True) + self.pmos = factory.create(module_type="ptx", + width=self.pmos_width, + mults=self.tx_mults, + tx_type="pmos", + connect_poly=True, + connect_active=True) self.add_mod(self.pmos) def setup_layout_constants(self): diff --git a/compiler/pgates/precharge.py b/compiler/pgates/precharge.py index 64ff98a1..cea9c845 100644 --- a/compiler/pgates/precharge.py +++ b/compiler/pgates/precharge.py @@ -2,7 +2,6 @@ import contact import pgate import debug from tech import drc, parameter -from ptx import ptx from vector import vector from globals import OPTS from sram_factory import factory @@ -50,8 +49,9 @@ class precharge(pgate.pgate): """ Initializes the upper and lower pmos """ - self.pmos = ptx(width=self.ptx_width, - tx_type="pmos") + self.pmos = factory.create(module_type="ptx", + width=self.ptx_width, + tx_type="pmos") self.add_mod(self.pmos) diff --git a/compiler/pgates/single_level_column_mux.py b/compiler/pgates/single_level_column_mux.py index 4b5db508..f03a22e8 100644 --- a/compiler/pgates/single_level_column_mux.py +++ b/compiler/pgates/single_level_column_mux.py @@ -3,7 +3,6 @@ import debug from tech import drc from vector import vector import contact -from ptx import ptx from globals import OPTS from sram_factory import factory @@ -48,7 +47,7 @@ class single_level_column_mux(design.design): # Adds nmos_lower,nmos_upper to the module self.ptx_width = self.tx_size*drc("minwidth_tx") - self.nmos = ptx(width=self.ptx_width) + self.nmos = factory.create(module_type="ptx", width=self.ptx_width) self.add_mod(self.nmos) From 91636be642de013f0bc3fce1d682e3e56f419dab Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 16 Jan 2019 16:56:06 -0800 Subject: [PATCH 14/44] Convert all contacts to use the sram_factory --- compiler/base/contact.py | 18 ++++++++++-------- compiler/base/hierarchy_layout.py | 28 ++++++++++++++++------------ compiler/base/route.py | 6 ++++-- compiler/base/wire.py | 11 +++++++---- compiler/options.py | 1 + compiler/pgates/pnor2.py | 14 +++++--------- compiler/pgates/ptx.py | 7 ++++--- 7 files changed, 47 insertions(+), 38 deletions(-) diff --git a/compiler/base/contact.py b/compiler/base/contact.py index db415179..f5cfcb0b 100644 --- a/compiler/base/contact.py +++ b/compiler/base/contact.py @@ -16,7 +16,9 @@ class contact(hierarchy_design.hierarchy_design): hierarchy as the contact. """ - def __init__(self, layer_stack, dimensions=[1,1], implant_type=None, well_type=None): + def __init__(self, layer_stack, dimensions=[1,1], implant_type=None, well_type=None, name=""): + # This will ignore the name parameter since we can guarantee a unique name here + if implant_type or well_type: name = "{0}_{1}_{2}_{3}x{4}_{5}{6}".format(layer_stack[0], layer_stack[1], @@ -164,13 +166,13 @@ class contact(hierarchy_design.hierarchy_design): """ Get total power of a module """ return self.return_power() - +from sram_factory import factory # This is not instantiated and used for calculations only. # These are static 1x1 contacts to reuse in all the design modules. -well = contact(layer_stack=("active", "contact", "metal1")) -active = contact(layer_stack=("active", "contact", "poly")) -poly = contact(layer_stack=("poly", "contact", "metal1")) -m1m2 = contact(layer_stack=("metal1", "via1", "metal2")) -m2m3 = contact(layer_stack=("metal2", "via2", "metal3")) -m3m4 = contact(layer_stack=("metal3", "via3", "metal4")) +well = factory.create(module_type="contact", layer_stack=("active", "contact", "metal1")) +active = factory.create(module_type="contact", layer_stack=("active", "contact", "poly")) +poly = factory.create(module_type="contact", layer_stack=("poly", "contact", "metal1")) +m1m2 = factory.create(module_type="contact", layer_stack=("metal1", "via1", "metal2")) +m2m3 = factory.create(module_type="contact", layer_stack=("metal2", "via2", "metal3")) +m3m4 = factory.create(module_type="contact", layer_stack=("metal3", "via3", "metal4")) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index c35f0709..60a596bb 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -378,11 +378,12 @@ class layout(): def add_via(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None): """ Add a three layer via structure. """ - import contact - via = contact.contact(layer_stack=layers, - dimensions=size, - implant_type=implant_type, - well_type=well_type) + from sram_factory import factory + via = factory.create(module_type="contact", + layer_stack=layers, + dimensions=size, + implant_type=implant_type, + well_type=well_type) self.add_mod(via) inst=self.add_inst(name=via.name, mod=via, @@ -395,11 +396,12 @@ class layout(): def add_via_center(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None): """ Add a three layer via structure by the center coordinate accounting for mirroring and rotation. """ - import contact - via = contact.contact(layer_stack=layers, - dimensions=size, - implant_type=implant_type, - well_type=well_type) + from sram_factory import factory + via = factory.create(module_type="contact", + layer_stack=layers, + dimensions=size, + implant_type=implant_type, + well_type=well_type) height = via.height width = via.width debug.check(mirror=="R0","Use rotate to rotate vias instead of mirror.") @@ -1039,9 +1041,11 @@ class layout(): # Find the number of vias for this pitch self.supply_vias = 1 - import contact + from sram_factory import factory while True: - c=contact.contact(("metal1","via1","metal2"), (self.supply_vias, self.supply_vias)) + c=factory.create(module_type="contact", + layer_stack=("metal1","via1","metal2"), + dimensions=(self.supply_vias, self.supply_vias)) if c.second_layer_width < self.supply_rail_width and c.second_layer_height < self.supply_rail_width: self.supply_vias += 1 else: diff --git a/compiler/base/route.py b/compiler/base/route.py index 09925e07..c6ce906b 100644 --- a/compiler/base/route.py +++ b/compiler/base/route.py @@ -1,10 +1,10 @@ from tech import drc import debug from design import design -from contact import contact from itertools import tee from vector import vector from vector3d import vector3d +from sram_factory import factory class route(design): """ @@ -45,7 +45,9 @@ class route(design): self.horiz_layer_width = drc("minwidth_{0}".format(self.horiz_layer_name)) # offset this by 1/2 the via size - self.c=contact(self.layer_stack, (self.num_vias, self.num_vias)) + self.c=factory.create(module_type="contact", + layer_stack=self.layer_stack, + dimensions=(self.num_vias, self.num_vias)) def create_wires(self): diff --git a/compiler/base/wire.py b/compiler/base/wire.py index 1565d10e..8500e502 100644 --- a/compiler/base/wire.py +++ b/compiler/base/wire.py @@ -1,7 +1,7 @@ from tech import drc import debug -from contact import contact from path import path +from sram_factory import factory class wire(path): """ @@ -37,15 +37,18 @@ class wire(path): self.horiz_layer_name = horiz_layer self.horiz_layer_width = drc("minwidth_{0}".format(horiz_layer)) - via_connect = contact(self.layer_stack, - (1, 1)) + via_connect = factory.create(module_type="contact", + layer_stack=self.layer_stack, + dimensions=(1, 1)) self.node_to_node = [drc("minwidth_" + str(self.horiz_layer_name)) + via_connect.width, drc("minwidth_" + str(self.horiz_layer_name)) + via_connect.height] # create a 1x1 contact def create_vias(self): """ Add a via and corner square at every corner of the path.""" - self.c=contact(self.layer_stack, (1, 1)) + self.c=factory.create(module_type="contact", + layer_stack=self.layer_stack, + dimensions=(1, 1)) c_width = self.c.width c_height = self.c.height diff --git a/compiler/options.py b/compiler/options.py index d1a9d7d8..fc1eb7d1 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -82,6 +82,7 @@ class options(optparse.Values): dff_array = "dff_array" dff = "dff" precharge_array = "precharge_array" + ptx = "ptx" replica_bitcell = "replica_bitcell" replica_bitline = "replica_bitline" sense_amp_array = "sense_amp_array" diff --git a/compiler/pgates/pnor2.py b/compiler/pgates/pnor2.py index b28d4cd1..93a0fd36 100644 --- a/compiler/pgates/pnor2.py +++ b/compiler/pgates/pnor2.py @@ -1,9 +1,9 @@ -import contact import pgate import debug from tech import drc, parameter, spice from vector import vector from globals import OPTS +import contact from sram_factory import factory class pnor2(pgate.pgate): @@ -72,15 +72,11 @@ class pnor2(pgate.pgate): def setup_layout_constants(self): """ Pre-compute some handy layout parameters. """ - poly_contact = contact.contact(("poly","contact","metal1")) - m1m2_via = contact.contact(("metal1","via1","metal2")) - m2m3_via = contact.contact(("metal2","via2","metal3")) - # metal spacing to allow contacts on any layer - self.input_spacing = max(self.poly_space + poly_contact.first_layer_width, - self.m1_space + m1m2_via.first_layer_width, - self.m2_space + m2m3_via.first_layer_width, - self.m3_space + m2m3_via.second_layer_width) + self.input_spacing = max(self.poly_space + contact.poly.first_layer_width, + self.m1_space + contact.m1m2.first_layer_width, + self.m2_space + contact.m2m3.first_layer_width, + self.m3_space + contact.m2m3.second_layer_width) # Compute the other pmos2 location, but determining offset to overlap the # source and drain pins diff --git a/compiler/pgates/ptx.py b/compiler/pgates/ptx.py index 6c81aaee..3d7ce296 100644 --- a/compiler/pgates/ptx.py +++ b/compiler/pgates/ptx.py @@ -2,9 +2,9 @@ import design import debug from tech import drc, spice from vector import vector -from contact import contact from globals import OPTS import path +from sram_factory import factory class ptx(design.design): """ @@ -97,8 +97,9 @@ class ptx(design.design): # This is not actually instantiated but used for calculations - self.active_contact = contact(layer_stack=("active", "contact", "metal1"), - dimensions=(1, self.num_contacts)) + self.active_contact = factory.create(module_type="contact", + layer_stack=("active", "contact", "metal1"), + dimensions=(1, self.num_contacts)) # The contacted poly pitch (or uncontacted in an odd technology) From 9ecfaf16ea90872c846358b9e914dde05d6921ed Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 16 Jan 2019 17:04:28 -0800 Subject: [PATCH 15/44] Add the factory class --- compiler/base/sram_factory.py | 78 ++++++++++++++++++++++++++++++ compiler/tests/04_pbitcell_test.py | 3 +- 2 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 compiler/base/sram_factory.py diff --git a/compiler/base/sram_factory.py b/compiler/base/sram_factory.py new file mode 100644 index 00000000..21aa7027 --- /dev/null +++ b/compiler/base/sram_factory.py @@ -0,0 +1,78 @@ +import debug +from globals import OPTS +from importlib import reload + + +class sram_factory: + """ + This is a factory pattern to create modules for usage in an SRAM. + Since GDSII has a flat namespace, it requires modules to have unique + names if their layout differs. This module ensures that any module + with different layouts will have different names. It also ensures that + identical layouts will share the same name to reduce file size and promote + hierarchical sharing. + """ + + def __init__(self): + # A dictionary of modules indexed by module type + self.modules = {} + # These are the indices to append to name to make unique object names + self.module_indices = {} + # A dictionary of instance lists indexed by module type + self.objects = {} + + def reset(self): + """ + Clear the factory instances for testing. + """ + self.__init__() + + def create(self, module_type, **kwargs): + """ + A generic function to create a module with a given module_type. The args + are passed directly to the module constructor. + """ + # if name!="": + # # This is a special case where the name and type don't match + # # Can't be overridden in the config file + # module_name = name + if hasattr(OPTS, module_type): + # Retrieve the name from OPTS if it exists, + # otherwise just use the name + module_name = getattr(OPTS, module_type) + else: + module_name = module_type + + # Either retrieve the already loaded module or load it + try: + mod = self.modules[module_type] + except KeyError: + c = reload(__import__(module_name)) + mod = getattr(c, module_name) + self.modules[module_type] = mod + self.module_indices[module_type] = 0 + self.objects[module_type] = [] + + # Either retreive a previous object or create a new one + for obj in self.objects[module_type]: + (obj_kwargs, obj_item) = obj + # Must have the same dictionary exactly (conservative) + if obj_kwargs == kwargs: + debug.info(1, "Existing module: type={0} name={1} kwargs={2}".format(module_type, obj_item.name, str(kwargs))) + return obj_item + + # Use the default name if there are default arguments + # This is especially for library cells so that the spice and gds files can be found. + if len(kwargs)>0: + # Create a unique name and increment the index + module_name = "{0}_{1}".format(module_name, self.module_indices[module_type]) + self.module_indices[module_type] += 1 + debug.info(1, "New module: type={0} name={1} kwargs={2}".format(module_type,module_name,str(kwargs))) + obj = mod(name=module_name,**kwargs) + self.objects[module_type].append((kwargs,obj)) + return obj + + +# Make a factory +factory = sram_factory() + diff --git a/compiler/tests/04_pbitcell_test.py b/compiler/tests/04_pbitcell_test.py index 9dd9341c..96e6bba8 100755 --- a/compiler/tests/04_pbitcell_test.py +++ b/compiler/tests/04_pbitcell_test.py @@ -17,9 +17,8 @@ class pbitcell_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) - from pbitcell import pbitcell - import tech + OPTS.num_rw_ports=1 OPTS.num_w_ports=1 OPTS.num_r_ports=1 From 7a152ea13d824ac10770ee8583c65bb43f412b14 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 16 Jan 2019 17:06:29 -0800 Subject: [PATCH 16/44] Move sram_factory to root dir --- compiler/{base => }/sram_factory.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename compiler/{base => }/sram_factory.py (100%) diff --git a/compiler/base/sram_factory.py b/compiler/sram_factory.py similarity index 100% rename from compiler/base/sram_factory.py rename to compiler/sram_factory.py From 9c8090d94bf0878125b656314d3a3fd6b836589e Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Wed, 16 Jan 2019 19:56:23 -0800 Subject: [PATCH 17/44] added debug.info to logging --- compiler/debug.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/debug.py b/compiler/debug.py index ea5eb45c..6a595569 100644 --- a/compiler/debug.py +++ b/compiler/debug.py @@ -70,3 +70,6 @@ def info(lev, str): else: class_name=mod.__name__ print("[{0}/{1}]: {2}".format(class_name,frm[0].f_code.co_name,str)) + log("[{0}/{1}]: {2}".format(class_name,frm[0].f_code.co_name,str)) + + From c20fb2a70e24f13e6d17d23905cc4d76fcaa149e Mon Sep 17 00:00:00 2001 From: Yusu Wang Date: Thu, 17 Jan 2019 12:01:08 -0800 Subject: [PATCH 18/44] replace matrix to array --- compiler/gdsMill/gdsMill/vlsiLayout.py | 44 ++++++++++++-------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/compiler/gdsMill/gdsMill/vlsiLayout.py b/compiler/gdsMill/gdsMill/vlsiLayout.py index 42921812..8d4816f6 100644 --- a/compiler/gdsMill/gdsMill/vlsiLayout.py +++ b/compiler/gdsMill/gdsMill/vlsiLayout.py @@ -1,7 +1,8 @@ from .gdsPrimitives import * from datetime import * #from mpmath import matrix -from numpy import matrix +#from numpy import matrix +import numpy as np #import gdsPrimitives import debug @@ -170,21 +171,20 @@ class VlsiLayout: else: # MRG: Added negative to make CCW rotate 8/29/18 angle = math.radians(float(rotateAngle)) - mRotate = matrix([[math.cos(angle),-math.sin(angle),0.0], + mRotate = np.array([[math.cos(angle),-math.sin(angle),0.0], [math.sin(angle),math.cos(angle),0.0], [0.0,0.0,1.0]]) #set up the translation matrix translateX = float(coordinates[0]) translateY = float(coordinates[1]) - mTranslate = matrix([[1.0,0.0,translateX],[0.0,1.0,translateY],[0.0,0.0,1.0]]) + mTranslate = np.array([[1.0,0.0,translateX],[0.0,1.0,translateY],[0.0,0.0,1.0]]) #set up the scale matrix (handles mirror X) scaleX = 1.0 if(transFlags[0]): scaleY = -1.0 else: scaleY = 1.0 - mScale = matrix([[scaleX,0.0,0.0],[0.0,scaleY,0.0],[0.0,0.0,1.0]]) - + mScale = np.array([[scaleX,0.0,0.0],[0.0,scaleY,0.0],[0.0,0.0,1.0]]) #we need to keep track of all transforms in the hierarchy #when we add an element to the xy tree, we apply all transforms from the bottom up transformPath.append((mRotate,mScale,mTranslate)) @@ -219,27 +219,26 @@ class VlsiLayout: def populateCoordinateMap(self): def addToXyTree(startingStructureName = None,transformPath = None): - #print("populateCoordinateMap") - uVector = matrix([1.0,0.0,0.0]).transpose() #start with normal basis vectors - vVector = matrix([0.0,1.0,0.0]).transpose() - origin = matrix([0.0,0.0,1.0]).transpose() #and an origin (Z component is 1.0 to indicate position instead of vector) + uVector = np.array([[1.0],[0.0],[0.0]]) #start with normal basis vectors + vVector = np.array([[0.0],[1.0],[0.0]]) + origin = np.array([[0.0],[0.0],[1.0]]) #and an origin (Z component is 1.0 to indicate position instead of vector) #make a copy of all the transforms and reverse it reverseTransformPath = transformPath[:] if len(reverseTransformPath) > 1: - reverseTransformPath.reverse() + reverseTransformPath.reverse() #now go through each transform and apply them to our basis and origin in succession for transform in reverseTransformPath: - origin = transform[0] * origin #rotate - uVector = transform[0] * uVector #rotate - vVector = transform[0] * vVector #rotate - origin = transform[1] * origin #scale - uVector = transform[1] * uVector #scale - vVector = transform[1] * vVector #scale - origin = transform[2] * origin #translate + origin = np.dot(transform[0], origin) #rotate + uVector = np.dot(transform[0], uVector) #rotate + vVector = np.dot(transform[0], vVector) #rotate + origin = np.dot(transform[1], origin) #scale + uVector = np.dot(transform[1], uVector) #scale + vVector = np.dot(transform[1], vVector) #scale + origin = np.dot(transform[2], origin) #translate #we don't need to do a translation on the basis vectors #uVector = transform[2] * uVector #translate #vVector = transform[2] * vVector #translate - #populate the xyTree with each structureName and coordinate space + #populate the xyTree with each structureName and coordinate space self.xyTree.append((startingStructureName,origin,uVector,vVector)) self.traverseTheHierarchy(delegateFunction = addToXyTree) @@ -522,8 +521,7 @@ class VlsiLayout: return True - def fillAreaDensity(self, layerToFill = 0, offsetInMicrons = (0,0), coverageWidth = 100.0, coverageHeight = 100.0, - minSpacing = 0.22, blockSize = 1.0): + def fillAreaDensity(self, layerToFill = 0, offsetInMicrons = (0,0), coverageWidth = 100.0, coverageHeight = 100.0, minSpacing = 0.22, blockSize = 1.0): effectiveBlock = blockSize+minSpacing widthInBlocks = int(coverageWidth/effectiveBlock) heightInBlocks = int(coverageHeight/effectiveBlock) @@ -810,8 +808,8 @@ class VlsiLayout: # This is fixed to be: # |u[0] v[0]| |x| |x'| # |u[1] v[1]|x|y|=|y'| - x=coordinate[0]*uVector[0].item()+coordinate[1]*vVector[0].item() - y=coordinate[0]*uVector[1].item()+coordinate[1]*vVector[1].item() + x=coordinate[0]*uVector[0][0]+coordinate[1]*vVector[0][0] + y=coordinate[0]*uVector[1][0]+coordinate[1]*vVector[1][0] transformCoordinate=[x,y] return transformCoordinate @@ -836,5 +834,3 @@ def boundaryArea(A): area_A=(A[2]-A[0])*(A[3]-A[1]) return area_A - - From bfca51f7348e9834e4b5a488349c3d3ea56dbef9 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Fri, 18 Jan 2019 09:51:52 -0800 Subject: [PATCH 19/44] Fix flatten work-around code to have new circuit names --- technology/scn4m_subm/mag_lib/setup.tcl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/technology/scn4m_subm/mag_lib/setup.tcl b/technology/scn4m_subm/mag_lib/setup.tcl index caf7550b..084428b5 100644 --- a/technology/scn4m_subm/mag_lib/setup.tcl +++ b/technology/scn4m_subm/mag_lib/setup.tcl @@ -4,11 +4,12 @@ equate class {-circuit1 nfet} {-circuit2 n} equate class {-circuit1 pfet} {-circuit2 p} # This circuit has symmetries and needs to be flattened to resolve them # or the banks won't pass -flatten class {-circuit1 bitcell_array} +flatten class {-circuit1 bitcell_array_0} +flatten class {-circuit1 bitcell_array_1} +flatten class {-circuit1 precharge_array_0} flatten class {-circuit1 precharge_array_1} flatten class {-circuit1 precharge_array_2} flatten class {-circuit1 precharge_array_3} -flatten class {-circuit1 precharge_array_4} property {-circuit1 nfet} remove as ad ps pd property {-circuit1 pfet} remove as ad ps pd property {-circuit2 n} remove as ad ps pd From 23718b952fd71bb0cdd9af59981da8be39bf58ab Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Fri, 18 Jan 2019 10:16:55 -0800 Subject: [PATCH 20/44] Check for print statements in more files since we now use print_raw --- compiler/tests/00_code_format_check_test.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/compiler/tests/00_code_format_check_test.py b/compiler/tests/00_code_format_check_test.py index 869e81bd..98799ee8 100755 --- a/compiler/tests/00_code_format_check_test.py +++ b/compiler/tests/00_code_format_check_test.py @@ -25,17 +25,11 @@ class code_format_test(openram_test): for code in source_codes: if re.search("gdsMill", code): continue - if re.search("options.py$", code): - continue if re.search("debug.py$", code): continue - if re.search("testutils.py$", code): - continue - if re.search("globals.py$", code): - continue if re.search("openram.py$", code): continue - if re.search("sram.py$", code): + if re.search("testutils.py$", code): continue if re.search("gen_stimulus.py$", code): continue From 978990f4dd9c723835bb066564523f4991688337 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Tue, 22 Jan 2019 15:24:38 -0800 Subject: [PATCH 21/44] cleaned up debug.py edits --- compiler/debug.py | 69 ++++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/compiler/debug.py b/compiler/debug.py index 6a595569..ed03881f 100644 --- a/compiler/debug.py +++ b/compiler/debug.py @@ -9,29 +9,37 @@ import sys # 2 = verbose # n = custom setting -def check(check,str): + +def check(check, str): (frame, filename, line_number, function_name, lines, index) = inspect.getouterframes(inspect.currentframe())[1] if not check: - sys.stderr.write("ERROR: file {0}: line {1}: {2}\n".format(os.path.basename(filename),line_number,str)) - log("ERROR: file {0}: line {1}: {2}\n".format(os.path.basename(filename),line_number,str)) + sys.stderr.write("ERROR: file {0}: line {1}: {2}\n".format( + os.path.basename(filename), line_number, str)) + log("ERROR: file {0}: line {1}: {2}\n".format( + os.path.basename(filename), line_number, str)) assert 0 -def error(str,return_value=0): + +def error(str, return_value=0): (frame, filename, line_number, function_name, lines, index) = inspect.getouterframes(inspect.currentframe())[1] - sys.stderr.write("ERROR: file {0}: line {1}: {2}\n".format(os.path.basename(filename),line_number,str)) - log("ERROR: file {0}: line {1}: {2}\n".format(os.path.basename(filename),line_number,str)) + sys.stderr.write("ERROR: file {0}: line {1}: {2}\n".format( + os.path.basename(filename), line_number, str)) + log("ERROR: file {0}: line {1}: {2}\n".format( + os.path.basename(filename), line_number, str)) + + assert return_value == 0 - assert return_value==0 def warning(str): (frame, filename, line_number, function_name, lines, index) = inspect.getouterframes(inspect.currentframe())[1] - sys.stderr.write("WARNING: file {0}: line {1}: {2}\n".format(os.path.basename(filename),line_number,str)) - log("WARNING: file {0}: line {1}: {2}\n".format(os.path.basename(filename),line_number,str)) - + sys.stderr.write("WARNING: file {0}: line {1}: {2}\n".format( + os.path.basename(filename), line_number, str)) + log("WARNING: file {0}: line {1}: {2}\n".format( + os.path.basename(filename), line_number, str)) def print_raw(str): @@ -40,36 +48,29 @@ def print_raw(str): def log(str): - try: - if log.create_file: - compile_log = open(globals.OPTS.output_path + globals.OPTS.output_name + '.log',"w+") - log.create_file = 0 - else: - compile_log = open(globals.OPTS.output_path + globals.OPTS.output_name + '.log',"a") - - if len(log.setup_output) != 0: - for line in log.setup_output: - compile_log.write(line) - log.setup_output = [] - compile_log.write(str + '\n') - except: - log.setup_out.append(str + "\n") - -#use a static list of strings to store messages until the global paths are set up -log.setup_output = [] -log.create_file = 1 + print(str(log.create_file) + '\n') + if log.create_file: + compile_log = open(globals.OPTS.output_path + + globals.OPTS.output_name + '.log', "w") + log.create_file = 0 + else: + compile_log = open(globals.OPTS.output_path + + globals.OPTS.output_name + '.log', "a") + compile_log.write(str + '\n') +log.create_file = 1 + + + def info(lev, str): from globals import OPTS if (OPTS.debug_level >= lev): frm = inspect.stack()[1] mod = inspect.getmodule(frm[0]) - #classname = frm.f_globals['__name__'] + # classname = frm.f_globals['__name__'] if mod.__name__ == None: - class_name="" + class_name = "" else: - class_name=mod.__name__ - print("[{0}/{1}]: {2}".format(class_name,frm[0].f_code.co_name,str)) - log("[{0}/{1}]: {2}".format(class_name,frm[0].f_code.co_name,str)) - + class_name = mod.__name__ + print_raw("[{0}/{1}]: {2}".format(class_name, frm[0].f_code.co_name, str)) From ac17e719736e9eb8658d5f782169f166cbd0b3e0 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Tue, 22 Jan 2019 15:47:16 -0800 Subject: [PATCH 22/44] removed debug print statement --- compiler/debug.py | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/debug.py b/compiler/debug.py index ed03881f..271b874b 100644 --- a/compiler/debug.py +++ b/compiler/debug.py @@ -48,7 +48,6 @@ def print_raw(str): def log(str): - print(str(log.create_file) + '\n') if log.create_file: compile_log = open(globals.OPTS.output_path + globals.OPTS.output_name + '.log', "w") From b58fd030830a9eb5e8b0a4d7c86c6bd4d7f19b43 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 23 Jan 2019 12:03:52 -0800 Subject: [PATCH 23/44] Change pbuf/pinv to pdriver in control logic. --- compiler/modules/bank.py | 16 ++--- compiler/modules/control_logic.py | 75 +++++++++++++---------- compiler/modules/delay_chain.py | 2 +- compiler/modules/replica_bitline.py | 2 +- compiler/modules/wordline_driver.py | 4 +- compiler/modules/write_driver.py | 5 ++ compiler/modules/write_driver_array.py | 4 ++ compiler/pgates/pand2.py | 6 +- compiler/pgates/pbuf.py | 6 +- compiler/pgates/pdriver.py | 81 +++++++++++++++---------- compiler/pgates/pinv.py | 2 +- compiler/pgates/pinvbuf.py | 10 +-- compiler/pgates/pnand2.py | 2 +- compiler/pgates/pnand3.py | 2 +- compiler/sram_base.py | 30 +++++---- compiler/tests/04_pdriver_test.py | 10 +-- compiler/tests/16_control_logic_test.py | 10 +-- 17 files changed, 157 insertions(+), 110 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 77cde2cb..fc00e1c4 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -1253,20 +1253,22 @@ class bank(design.design): def get_wl_en_cin(self): """Get the relative capacitance of all the clk connections in the bank""" #wl_en only used in the wordline driver. - total_clk_cin = self.wordline_driver.get_wl_en_cin() - return total_clk_cin - + return self.wordline_driver.get_wl_en_cin() + + def get_w_en_cin(self): + """Get the relative capacitance of all the clk connections in the bank""" + #wl_en only used in the wordline driver. + return self.write_driver.get_w_en_cin() + def get_clk_bar_cin(self): """Get the relative capacitance of all the clk_bar connections in the bank""" #Current bank only uses clock bar (clk_buf_bar) as an enable for the precharge array. #Precharges are the all the same in Mulitport, one is picked port = self.read_ports[0] - total_clk_bar_cin = self.precharge_array[port].get_en_cin() - return total_clk_bar_cin + return self.precharge_array[port].get_en_cin() def get_sen_cin(self): """Get the relative capacitance of all the sense amp enable connections in the bank""" #Current bank only uses sen as an enable for the sense amps. - total_sen_cin = self.sense_amp_array.get_en_cin() - return total_sen_cin + return self.sense_amp_array.get_en_cin() diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index 52af5bbb..7d541307 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -14,20 +14,22 @@ class control_logic(design.design): Dynamically generated Control logic for the total SRAM circuit. """ - def __init__(self, num_rows, words_per_row, sram=None, port_type="rw"): + def __init__(self, num_rows, words_per_row, word_size, sram=None, port_type="rw"): """ Constructor """ name = "control_logic_" + port_type design.design.__init__(self, name) debug.info(1, "Creating {}".format(name)) + self.sram=sram self.num_rows = num_rows self.words_per_row = words_per_row + self.word_size = word_size self.port_type = port_type + + self.num_words = num_rows * words_per_row self.enable_delay_chain_resizing = False - #This is needed to resize the delay chain. Likely to be changed at some point. - self.sram=sram #self.sram=None #disable re-sizing for debugging, FIXME: resizing is not working, needs to be adjusted for new control logic. self.wl_timing_tolerance = 1 #Determines how much larger the sen delay should be. Accounts for possible error in model. self.parasitic_inv_delay = parameter["min_inv_para_delay"] #Keeping 0 for now until further testing. @@ -82,33 +84,44 @@ class control_logic(design.design): self.add_mod(self.and2) # Special gates: inverters for buffering - # Size the clock for the number of rows (fanout) - clock_driver_size = max(1,int(self.num_rows/4)) - self.clkbuf = factory.create(module_type="pbuf", - size=clock_driver_size, + # clk_buf drives a flop for every address and control bit + clock_fanout = math.log(self.num_words,2) + math.log(self.words_per_row,2) + self.num_control_signals + + self.clkbuf = factory.create(module_type="pdriver", + fanout=clock_fanout, height=dff_height) self.add_mod(self.clkbuf) - self.buf16 = factory.create(module_type="pbuf", - size=16, - height=dff_height) - self.add_mod(self.buf16) + # wl_en drives every row in the bank + self.wl_en_driver = factory.create(module_type="pdriver", + fanout=self.num_rows, + height=dff_height) + self.add_mod(self.wl_en_driver) - self.buf8 = factory.create(module_type="pbuf", - size=8, - height=dff_height) - self.add_mod(self.buf8) - - self.inv = self.inv1 = factory.create(module_type="pinv", + # w_en drives every write driver + self.w_en_driver = factory.create(module_type="pbuf", + size=self.word_size, + height=dff_height) + self.add_mod(self.w_en_driver) + + # s_en drives every sense amp + self.s_en_driver = factory.create(module_type="pbuf", + size=8, + height=dff_height) + self.add_mod(self.s_en_driver) + + # used to generate inverted signals with low fanout + self.inv = factory.create(module_type="pinv", size=1, height=dff_height) - self.add_mod(self.inv1) - - self.inv8 = factory.create(module_type="pinv", - size=8, - height=dff_height) - self.add_mod(self.inv8) + self.add_mod(self.inv) + + # p_en_bar drives every column in the bicell array + self.p_en_bar_driver = factory.create(module_type="pdriver", + fanout=8, + height=dff_height) + self.add_mod(self.p_en_bar_driver) if (self.port_type == "rw") or (self.port_type == "r"): delay_stages_heuristic, delay_fanout_heuristic = self.get_heuristic_delay_chain_size() @@ -510,7 +523,7 @@ class control_logic(design.design): def create_wlen_row(self): # input pre_p_en, output: wl_en self.wl_en_inst=self.add_inst(name="buf_wl_en", - mod=self.buf16) + mod=self.wl_en_driver) self.connect_inst(["gated_clk_bar", "wl_en", "vdd", "gnd"]) def place_wlen_row(self, row): @@ -580,7 +593,7 @@ class control_logic(design.design): # input: pre_p_en, output: p_en_bar self.p_en_bar_inst=self.add_inst(name="inv_p_en_bar", - mod=self.inv8) + mod=self.p_en_bar_driver) self.connect_inst([input_name, "p_en_bar", "vdd", "gnd"]) @@ -620,7 +633,7 @@ class control_logic(design.design): # BUFFER FOR S_EN # input: pre_s_en, output: s_en self.s_en_inst=self.add_inst(name="buf_s_en", - mod=self.buf8) + mod=self.s_en_driver) self.connect_inst(["pre_s_en", "s_en", "vdd", "gnd"]) def place_sen_row(self,row): @@ -657,7 +670,7 @@ class control_logic(design.design): # BUFFER FOR W_EN self.w_en_inst = self.add_inst(name="buf_w_en_buf", - mod=self.buf8) + mod=self.w_en_driver) self.connect_inst([input_name, "w_en", "vdd", "gnd"]) @@ -814,7 +827,7 @@ class control_logic(design.design): #Calculate the load on wl_en within the module and add it to external load external_cout = self.sram.get_wl_en_cin() #First stage is the clock buffer - stage_effort_list += self.clkbuf.get_output_stage_efforts(external_cout, is_clk_bar_rise) + stage_effort_list += self.clkbuf.get_stage_efforts(external_cout, is_clk_bar_rise) last_stage_is_rise = stage_effort_list[-1].is_rise #Then ask the sram for the other path delays (from the bank) @@ -845,17 +858,17 @@ class control_logic(design.design): #First stage, gated_clk_bar -(and2)-> rbl_in. Only for RW ports. if self.port_type == "rw": stage1_cout = self.replica_bitline.get_en_cin() - stage_effort_list += self.and2.get_output_stage_efforts(stage1_cout, last_stage_rise) + stage_effort_list += self.and2.get_stage_efforts(stage1_cout, last_stage_rise) last_stage_rise = stage_effort_list[-1].is_rise #Replica bitline stage, rbl_in -(rbl)-> pre_s_en - stage2_cout = self.buf8.get_cin() + stage2_cout = self.s_en_driver.get_cin() stage_effort_list += self.replica_bitline.determine_sen_stage_efforts(stage2_cout, last_stage_rise) last_stage_rise = stage_effort_list[-1].is_rise #buffer stage, pre_s_en -(buffer)-> s_en stage3_cout = self.sram.get_sen_cin() - stage_effort_list += self.buf8.get_output_stage_efforts(stage3_cout, last_stage_rise) + stage_effort_list += self.s_en_driver.get_stage_efforts(stage3_cout, last_stage_rise) last_stage_rise = stage_effort_list[-1].is_rise return stage_effort_list diff --git a/compiler/modules/delay_chain.py b/compiler/modules/delay_chain.py index 1478dbfc..848e4e85 100644 --- a/compiler/modules/delay_chain.py +++ b/compiler/modules/delay_chain.py @@ -230,7 +230,7 @@ class delay_chain(design.design): stage_cout = self.inv.get_cin()*(stage_fanout+1) if len(stage_effort_list) == len(self.fanout_list)-1: #last stage stage_cout+=ext_delayed_en_cout - stage = self.inv.get_effort_stage(stage_cout, last_stage_is_rise) + stage = self.inv.get_stage_effort(stage_cout, last_stage_is_rise) stage_effort_list.append(stage) last_stage_is_rise = stage.is_rise diff --git a/compiler/modules/replica_bitline.py b/compiler/modules/replica_bitline.py index 614e6d42..8d93b257 100644 --- a/compiler/modules/replica_bitline.py +++ b/compiler/modules/replica_bitline.py @@ -614,7 +614,7 @@ class replica_bitline(design.design): #The delay chain triggers the enable on the replica bitline (rbl). This is used to track the bitline delay whereas this #model is intended to track every but that. Therefore, the next stage is the inverter after the rbl. - stage2 = self.inv.get_effort_stage(ext_cout, last_stage_is_rise) + stage2 = self.inv.get_stage_effort(ext_cout, last_stage_is_rise) stage_effort_list.append(stage2) return stage_effort_list diff --git a/compiler/modules/wordline_driver.py b/compiler/modules/wordline_driver.py index 021b76d1..72f73a57 100644 --- a/compiler/modules/wordline_driver.py +++ b/compiler/modules/wordline_driver.py @@ -224,11 +224,11 @@ class wordline_driver(design.design): stage_effort_list = [] stage1_cout = self.inv.get_cin() - stage1 = self.nand2.get_effort_stage(stage1_cout, inp_is_rise) + stage1 = self.nand2.get_stage_effort(stage1_cout, inp_is_rise) stage_effort_list.append(stage1) last_stage_is_rise = stage1.is_rise - stage2 = self.inv.get_effort_stage(external_cout, last_stage_is_rise) + stage2 = self.inv.get_stage_effort(external_cout, last_stage_is_rise) stage_effort_list.append(stage2) return stage_effort_list diff --git a/compiler/modules/write_driver.py b/compiler/modules/write_driver.py index 8d1291a7..34c51245 100644 --- a/compiler/modules/write_driver.py +++ b/compiler/modules/write_driver.py @@ -23,3 +23,8 @@ class write_driver(design.design): self.height = write_driver.height self.pin_map = write_driver.pin_map + + def get_w_en_cin(self): + """Get the relative capacitance of a single input""" + # This is approximated from SCMOS. It has roughly 5 3x transistor gates. + return 5*3 diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index 4bcfbcb0..76eb9f84 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -130,3 +130,7 @@ class write_driver_array(design.design): + def get_w_en_cin(self): + """Get the relative capacitance of all the enable connections in the bank""" + #The enable is connected to a nand2 for every row. + return self.driver.get_w_en_cin() * len(self.driver_insts) diff --git a/compiler/pgates/pand2.py b/compiler/pgates/pand2.py index 0e1acde6..2d04eb34 100644 --- a/compiler/pgates/pand2.py +++ b/compiler/pgates/pand2.py @@ -113,15 +113,15 @@ class pand2(pgate.pgate): inv_delay = self.inv.analytical_delay(slew=nand_delay.slew, load=load) return nand_delay + inv_delay - def get_output_stage_efforts(self, external_cout, inp_is_rise=False): + def get_stage_efforts(self, external_cout, inp_is_rise=False): """Get the stage efforts of the A or B -> Z path""" stage_effort_list = [] stage1_cout = self.inv.get_cin() - stage1 = self.nand.get_effort_stage(stage1_cout, inp_is_rise) + stage1 = self.nand.get_stage_effort(stage1_cout, inp_is_rise) stage_effort_list.append(stage1) last_stage_is_rise = stage1.is_rise - stage2 = self.inv.get_effort_stage(external_cout, last_stage_is_rise) + stage2 = self.inv.get_stage_effort(external_cout, last_stage_is_rise) stage_effort_list.append(stage2) return stage_effort_list diff --git a/compiler/pgates/pbuf.py b/compiler/pgates/pbuf.py index a86aea1c..3789ffc2 100644 --- a/compiler/pgates/pbuf.py +++ b/compiler/pgates/pbuf.py @@ -115,15 +115,15 @@ class pbuf(pgate.pgate): inv2_delay = self.inv2.analytical_delay(slew=inv1_delay.slew, load=load) return inv1_delay + inv2_delay - def get_output_stage_efforts(self, external_cout, inp_is_rise=False): + def get_stage_efforts(self, external_cout, inp_is_rise=False): """Get the stage efforts of the A -> Z path""" stage_effort_list = [] stage1_cout = self.inv2.get_cin() - stage1 = self.inv1.get_effort_stage(stage1_cout, inp_is_rise) + stage1 = self.inv1.get_stage_effort(stage1_cout, inp_is_rise) stage_effort_list.append(stage1) last_stage_is_rise = stage1.is_rise - stage2 = self.inv2.get_effort_stage(external_cout, last_stage_is_rise) + stage2 = self.inv2.get_stage_effort(external_cout, last_stage_is_rise) stage_effort_list.append(stage2) return stage_effort_list diff --git a/compiler/pgates/pdriver.py b/compiler/pgates/pdriver.py index 934412d6..4f440261 100644 --- a/compiler/pgates/pdriver.py +++ b/compiler/pgates/pdriver.py @@ -11,16 +11,16 @@ class pdriver(pgate.pgate): """ This instantiates an even or odd number of inverters sized for driving a load. """ - def __init__(self, name, neg_polarity=False, fanout_size=8, size_list = [], height=None): + def __init__(self, name, neg_polarity=False, fanout=0, size_list=None, height=None): self.stage_effort = 4 self.height = height self.neg_polarity = neg_polarity self.size_list = size_list - self.fanout_size = fanout_size + self.fanout = fanout - if len(self.size_list) > 0 and (self.fanout_size != 8 or self.neg_polarity): - debug.error("Cannot specify both size_list and neg_polarity or fanout_size.", -1) + if self.size_list and (self.fanout != 0 or self.neg_polarity): + debug.error("Cannot specify both size_list and neg_polarity or fanout.", -1) pgate.pgate.__init__(self, name, height) debug.info(1, "Creating {}".format(self.name)) @@ -33,14 +33,14 @@ class pdriver(pgate.pgate): def compute_sizes(self): # size_list specified - if len(self.size_list) > 0: + if self.size_list: if not len(self.size_list) % 2: neg_polarity = True self.num_inv = len(self.size_list) else: # find the number of stages - #fanout_size is a unit inverter fanout, not a capacitance so c_in=1 - num_stages = max(1,int(round(log(self.fanout_size)/log(4)))) + #fanout is a unit inverter fanout, not a capacitance so c_in=1 + num_stages = max(1,int(round(log(self.fanout)/log(4)))) # find inv_num and compute sizes if self.neg_polarity: @@ -53,42 +53,42 @@ class pdriver(pgate.pgate): self.same_polarity(num_stages=num_stages) else: self.diff_polarity(num_stages=num_stages) - + def same_polarity(self, num_stages): - self.calc_size_list = [] + self.size_list = [] self.num_inv = num_stages # compute sizes - fanout_size_prev = self.fanout_size + fanout_prev = self.fanout for x in range(self.num_inv-1,-1,-1): - fanout_size_prev = int(round(fanout_size_prev/self.stage_effort)) - self.calc_size_list.append(fanout_size_prev) + fanout_prev = max(round(fanout_prev/self.stage_effort),1) + self.size_list.append(fanout_prev) + self.size_list.reverse() def diff_polarity(self, num_stages): - self.calc_size_list = [] + self.size_list = [] # find which delay is smaller if (num_stages > 1): - delay_below = ((num_stages-1)*(self.fanout_size**(1/num_stages-1))) + num_stages-1 - delay_above = ((num_stages+1)*(self.fanout_size**(1/num_stages+1))) + num_stages+1 + delay_below = ((num_stages-1)*(self.fanout**(1/num_stages-1))) + num_stages-1 + delay_above = ((num_stages+1)*(self.fanout**(1/num_stages+1))) + num_stages+1 if (delay_above < delay_below): # recompute stage_effort for this delay self.num_inv = num_stages+1 - polarity_stage_effort = self.fanout_size**(1/self.num_inv) + polarity_stage_effort = self.fanout**(1/self.num_inv) else: self.num_inv = num_stages-1 - polarity_stage_effort = self.fanout_size**(1/self.num_inv) + polarity_stage_effort = self.fanout**(1/self.num_inv) else: # num_stages is 1, can't go to 0 self.num_inv = num_stages+1 - polarity_stage_effort = self.fanout_size**(1/self.num_inv) + polarity_stage_effort = self.fanout**(1/self.num_inv) - # compute sizes - fanout_size_prev = self.fanout_size + fanout_prev = self.fanout for x in range(self.num_inv-1,-1,-1): - fanout_size_prev = int(round(fanout_size_prev/polarity_stage_effort)) - self.calc_size_list.append(fanout_size_prev) - + fanout_prev = round(fanout_prev/polarity_stage_effort) + self.size_list.append(fanout_prev) + self.size_list.reverse() def create_netlist(self): inv_list = [] @@ -115,16 +115,10 @@ class pdriver(pgate.pgate): def add_modules(self): self.inv_list = [] - if len(self.size_list) > 0: # size list specified - for x in range(len(self.size_list)): - temp_inv = factory.create(module_type="pinv", size=self.size_list[x], height=self.height) - self.inv_list.append(temp_inv) - self.add_mod(self.inv_list[x]) - else: # find inv sizes - for x in range(len(self.calc_size_list)): - temp_inv = factory.create(module_type="pinv", size=self.calc_size_list[x], height=self.height) - self.inv_list.append(temp_inv) - self.add_mod(self.inv_list[x]) + for size in self.size_list: + temp_inv = factory.create(module_type="pinv", size=size, height=self.height) + self.inv_list.append(temp_inv) + self.add_mod(temp_inv) def create_insts(self): @@ -226,3 +220,24 @@ class pdriver(pgate.pgate): return delay + def get_stage_efforts(self, external_cout, inp_is_rise=False): + """Get the stage efforts of the A -> Z path""" + + cout_list = {} + for prev_inv,inv in zip(self.inv_list, self.inv_list[1:]): + cout_list[prev_inv]=inv.get_cin() + + cout_list[self.inv_list[-1]]=external_cout + + stage_effort_list = [] + last_inp_is_rise = inp_is_rise + for inv in self.inv_list: + stage = inv.get_stage_effort(cout_list[inv], last_inp_is_rise) + stage_effort_list.append(stage) + last_inp_is_rise = stage.is_rise + + return stage_effort_list + + def get_cin(self): + """Returns the relative capacitance of the input""" + return self.inv_list[0].get_cin() diff --git a/compiler/pgates/pinv.py b/compiler/pgates/pinv.py index 0dc1b683..ac850d76 100644 --- a/compiler/pgates/pinv.py +++ b/compiler/pgates/pinv.py @@ -286,7 +286,7 @@ class pinv(pgate.pgate): """Return the capacitance of the gate connection in generic capacitive units relative to the minimum width of a transistor""" return self.nmos_size + self.pmos_size - def get_effort_stage(self, cout, inp_is_rise=True): + def get_stage_effort(self, cout, inp_is_rise=True): """Returns an object representing the parameters for delay in tau units. Optional is_rise refers to the input direction rise/fall. Input inverted by this stage. """ diff --git a/compiler/pgates/pinvbuf.py b/compiler/pgates/pinvbuf.py index adce2d6c..3be4d7f1 100644 --- a/compiler/pgates/pinvbuf.py +++ b/compiler/pgates/pinvbuf.py @@ -186,11 +186,11 @@ class pinvbuf(design.design): """Get the stage efforts of the clk -> clk_buf path""" stage_effort_list = [] stage1_cout = self.inv1.get_cin() + self.inv2.get_cin() - stage1 = self.inv.get_effort_stage(stage1_cout, inp_is_rise) + stage1 = self.inv.get_stage_effort(stage1_cout, inp_is_rise) stage_effort_list.append(stage1) last_stage_is_rise = stage1.is_rise - stage2 = self.inv2.get_effort_stage(external_cout, last_stage_is_rise) + stage2 = self.inv2.get_stage_effort(external_cout, last_stage_is_rise) stage_effort_list.append(stage2) return stage_effort_list @@ -200,16 +200,16 @@ class pinvbuf(design.design): #After (almost) every stage, the direction of the signal inverts. stage_effort_list = [] stage1_cout = self.inv1.get_cin() + self.inv2.get_cin() - stage1 = self.inv.get_effort_stage(stage1_cout, inp_is_rise) + stage1 = self.inv.get_stage_effort(stage1_cout, inp_is_rise) stage_effort_list.append(stage1) last_stage_is_rise = stage_effort_list[-1].is_rise stage2_cout = self.inv2.get_cin() - stage2 = self.inv1.get_effort_stage(stage2_cout, last_stage_is_rise) + stage2 = self.inv1.get_stage_effort(stage2_cout, last_stage_is_rise) stage_effort_list.append(stage2) last_stage_is_rise = stage_effort_list[-1].is_rise - stage3 = self.inv2.get_effort_stage(external_cout, last_stage_is_rise) + stage3 = self.inv2.get_stage_effort(external_cout, last_stage_is_rise) stage_effort_list.append(stage3) return stage_effort_list diff --git a/compiler/pgates/pnand2.py b/compiler/pgates/pnand2.py index 8ff4b953..1ce87750 100644 --- a/compiler/pgates/pnand2.py +++ b/compiler/pgates/pnand2.py @@ -252,7 +252,7 @@ class pnand2(pgate.pgate): """Return the relative input capacitance of a single input""" return self.nmos_size+self.pmos_size - def get_effort_stage(self, cout, inp_is_rise=True): + def get_stage_effort(self, cout, inp_is_rise=True): """Returns an object representing the parameters for delay in tau units. Optional is_rise refers to the input direction rise/fall. Input inverted by this stage. """ diff --git a/compiler/pgates/pnand3.py b/compiler/pgates/pnand3.py index a4bbb1c0..cedf161f 100644 --- a/compiler/pgates/pnand3.py +++ b/compiler/pgates/pnand3.py @@ -264,7 +264,7 @@ class pnand3(pgate.pgate): """Return the relative input capacitance of a single input""" return self.nmos_size+self.pmos_size - def get_effort_stage(self, cout, inp_is_rise=True): + def get_stage_effort(self, cout, inp_is_rise=True): """Returns an object representing the parameters for delay in tau units. Optional is_rise refers to the input direction rise/fall. Input inverted by this stage. """ diff --git a/compiler/sram_base.py b/compiler/sram_base.py index 39f139c6..61d3639d 100644 --- a/compiler/sram_base.py +++ b/compiler/sram_base.py @@ -279,20 +279,23 @@ class sram_base(design, verilog, lef): # Create the control logic module for each port type if len(self.readwrite_ports)>0: - self.control_logic_rw = self.mod_control_logic(num_rows=self.num_rows, + self.control_logic_rw = self.mod_control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row, + word_size=self.word_size, sram=self, port_type="rw") self.add_mod(self.control_logic_rw) if len(self.writeonly_ports)>0: self.control_logic_w = self.mod_control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row, + word_size=self.word_size, sram=self, port_type="w") self.add_mod(self.control_logic_w) if len(self.readonly_ports)>0: self.control_logic_r = self.mod_control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row, + word_size=self.word_size, sram=self, port_type="r") self.add_mod(self.control_logic_r) @@ -512,25 +515,30 @@ class sram_base(design, verilog, lef): def get_wl_en_cin(self): """Gets the capacitive load the of clock (clk_buf) for the sram""" - #As clk_buf is an output of the control logic. The cap for that module is not determined here. #Only the wordline drivers within the bank use this signal - bank_clk_cin = self.bank.get_wl_en_cin() - - return bank_clk_cin - + return self.bank.get_wl_en_cin() + + def get_w_en_cin(self): + """Gets the capacitive load the of write enable (w_en) for the sram""" + #Only the write drivers within the bank use this signal + return self.bank.get_w_en_cin() + + + def get_p_en_bar_cin(self): + """Gets the capacitive load the of precharge enable (p_en_bar) for the sram""" + #Only the precharges within the bank use this signal + return self.bank.get_p_en_bar_cin() + def get_clk_bar_cin(self): """Gets the capacitive load the of clock (clk_buf_bar) for the sram""" #As clk_buf_bar is an output of the control logic. The cap for that module is not determined here. #Only the precharge cells use this signal (other than the control logic) - bank_clk_cin = self.bank.get_clk_bar_cin() - return bank_clk_cin + return self.bank.get_clk_bar_cin() def get_sen_cin(self): """Gets the capacitive load the of sense amp enable for the sram""" - #As clk_buf_bar is an output of the control logic. The cap for that module is not determined here. #Only the sense_amps use this signal (other than the control logic) - bank_sen_cin = self.bank.get_sen_cin() - return bank_sen_cin + return self.bank.get_sen_cin() diff --git a/compiler/tests/04_pdriver_test.py b/compiler/tests/04_pdriver_test.py index ee1b8e1a..ba89961f 100755 --- a/compiler/tests/04_pdriver_test.py +++ b/compiler/tests/04_pdriver_test.py @@ -22,22 +22,22 @@ class pdriver_test(openram_test): debug.info(2, "Testing inverter/buffer 4x 8x") # a tests the error message for specifying conflicting conditions - #a = pdriver.pdriver(fanout_size = 4,size_list = [1,2,4,8]) + #a = pdriver.pdriver(fanout = 4,size_list = [1,2,4,8]) #self.local_check(a) b = pdriver.pdriver(name="pdriver1", size_list = [1,2,4,8]) self.local_check(b) - c = pdriver.pdriver(name="pdriver2", fanout_size = 50) + c = pdriver.pdriver(name="pdriver2", fanout = 50) self.local_check(c) - d = pdriver.pdriver(name="pdriver3", fanout_size = 50, neg_polarity = True) + d = pdriver.pdriver(name="pdriver3", fanout = 50, neg_polarity = True) self.local_check(d) - e = pdriver.pdriver(name="pdriver4", fanout_size = 64) + e = pdriver.pdriver(name="pdriver4", fanout = 64) self.local_check(e) - f = pdriver.pdriver(name="pdriver5", fanout_size = 64, neg_polarity = True) + f = pdriver.pdriver(name="pdriver5", fanout = 64, neg_polarity = True) self.local_check(f) globals.end_openram() diff --git a/compiler/tests/16_control_logic_test.py b/compiler/tests/16_control_logic_test.py index 818c2eaf..91ad0500 100755 --- a/compiler/tests/16_control_logic_test.py +++ b/compiler/tests/16_control_logic_test.py @@ -20,7 +20,7 @@ class control_logic_test(openram_test): # check control logic for single port debug.info(1, "Testing sample for control_logic") - a = control_logic.control_logic(num_rows=128, words_per_row=1) + a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=32) self.local_check(a) # check control logic for multi-port @@ -31,7 +31,7 @@ class control_logic_test(openram_test): OPTS.num_r_ports = 0 debug.info(1, "Testing sample for control_logic for multiport") - a = control_logic.control_logic(num_rows=128, words_per_row=1) + a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8) self.local_check(a) # Check port specific control logic @@ -40,15 +40,15 @@ class control_logic_test(openram_test): OPTS.num_r_ports = 1 debug.info(1, "Testing sample for control_logic for multiport, only write control logic") - a = control_logic.control_logic(num_rows=128, words_per_row=1, port_type="rw") + a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8, port_type="rw") self.local_check(a) debug.info(1, "Testing sample for control_logic for multiport, only write control logic") - a = control_logic.control_logic(num_rows=128, words_per_row=1, port_type="w") + a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8, port_type="w") self.local_check(a) debug.info(1, "Testing sample for control_logic for multiport, only read control logic") - a = control_logic.control_logic(num_rows=128, words_per_row=1, port_type="r") + a = control_logic.control_logic(num_rows=128, words_per_row=1, word_size=8, port_type="r") self.local_check(a) globals.end_openram() From d64d262d78a6c030377acdc21ed3aeed3387fa5e Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 23 Jan 2019 12:51:28 -0800 Subject: [PATCH 24/44] Fix pdriver instantiation. Change sizes based on word_size. --- compiler/modules/control_logic.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index 7d541307..e2f93b16 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -26,6 +26,7 @@ class control_logic(design.design): self.word_size = word_size self.port_type = port_type + self.num_cols = word_size*words_per_row self.num_words = num_rows * words_per_row self.enable_delay_chain_resizing = False @@ -100,14 +101,14 @@ class control_logic(design.design): self.add_mod(self.wl_en_driver) # w_en drives every write driver - self.w_en_driver = factory.create(module_type="pbuf", - size=self.word_size, + self.w_en_driver = factory.create(module_type="pdriver", + fanout=self.word_size, height=dff_height) self.add_mod(self.w_en_driver) # s_en drives every sense amp - self.s_en_driver = factory.create(module_type="pbuf", - size=8, + self.s_en_driver = factory.create(module_type="pdriver", + fanout=self.word_size, height=dff_height) self.add_mod(self.s_en_driver) @@ -119,7 +120,7 @@ class control_logic(design.design): # p_en_bar drives every column in the bicell array self.p_en_bar_driver = factory.create(module_type="pdriver", - fanout=8, + fanout=self.num_cols, height=dff_height) self.add_mod(self.p_en_bar_driver) From 8a85d3141a06e1b1c19ba184ccb6e41cd2c3a78c Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 23 Jan 2019 13:08:43 -0800 Subject: [PATCH 25/44] Fix polarity problem. --- compiler/modules/control_logic.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index e2f93b16..9321ccd0 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -87,7 +87,7 @@ class control_logic(design.design): # Special gates: inverters for buffering # clk_buf drives a flop for every address and control bit clock_fanout = math.log(self.num_words,2) + math.log(self.words_per_row,2) + self.num_control_signals - + #clock_fanout = max(1,int(self.num_rows/4)) self.clkbuf = factory.create(module_type="pdriver", fanout=clock_fanout, height=dff_height) @@ -102,7 +102,7 @@ class control_logic(design.design): # w_en drives every write driver self.w_en_driver = factory.create(module_type="pdriver", - fanout=self.word_size, + fanout=self.word_size+8, height=dff_height) self.add_mod(self.w_en_driver) @@ -120,6 +120,7 @@ class control_logic(design.design): # p_en_bar drives every column in the bicell array self.p_en_bar_driver = factory.create(module_type="pdriver", + neg_polarity=True, fanout=self.num_cols, height=dff_height) self.add_mod(self.p_en_bar_driver) From 091b4e4c621d6575de0a16421749ac78cea90217 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 23 Jan 2019 17:27:15 -0800 Subject: [PATCH 26/44] Add size commments to spize. Change pdriver stage effort. --- compiler/base/hierarchy_spice.py | 11 ++++++++++- compiler/modules/control_logic.py | 3 +-- compiler/pgates/pand2.py | 2 +- compiler/pgates/pbuf.py | 3 ++- compiler/pgates/pdriver.py | 4 +++- compiler/pgates/pinv.py | 1 + compiler/pgates/pinvbuf.py | 1 + compiler/pgates/pnand2.py | 1 + compiler/pgates/pnand3.py | 1 + compiler/pgates/pnor2.py | 1 + 10 files changed, 22 insertions(+), 6 deletions(-) diff --git a/compiler/base/hierarchy_spice.py b/compiler/base/hierarchy_spice.py index 038cf0b7..424e4d94 100644 --- a/compiler/base/hierarchy_spice.py +++ b/compiler/base/hierarchy_spice.py @@ -19,13 +19,15 @@ class spice(): # Holds subckts/mods for this module self.mods = [] # Holds the pins for this module - self.pins = [] + self.pins = [] # The type map of each pin: INPUT, OUTPUT, INOUT, POWER, GROUND # for each instance, this is the set of nets/nodes that map to the pins for this instance self.pin_type = {} # THE CONNECTIONS MUST MATCH THE ORDER OF THE PINS (restriction imposed by the # Spice format) self.conns = [] + # Keep track of any comments to add the the spice + self.comments = [] self.sp_read() @@ -33,6 +35,10 @@ class spice(): # Spice circuit ############################################################ + def add_comment(self, comment): + """ Add a comment to the spice file """ + self.comments.append(comment) + def add_pin(self, name, pin_type="INOUT"): """ Adds a pin to the pins list. Default type is INOUT signal. """ self.pins.append(name) @@ -162,6 +168,9 @@ class spice(): sp.write("\n.SUBCKT {0} {1}\n".format(self.name, " ".join(self.pins))) + for line in self.comments: + sp.write("* {}\n".format(line)) + # every instance must have a set of connections, even if it is empty. if len(self.insts)!=len(self.conns): debug.error("{0} : Not all instance pins ({1}) are connected ({2}).".format(self.name, diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index 9321ccd0..594ebd2c 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -86,8 +86,7 @@ class control_logic(design.design): # Special gates: inverters for buffering # clk_buf drives a flop for every address and control bit - clock_fanout = math.log(self.num_words,2) + math.log(self.words_per_row,2) + self.num_control_signals - #clock_fanout = max(1,int(self.num_rows/4)) + clock_fanout = math.log(self.num_words,2) + math.log(self.words_per_row,2)+1 + self.num_control_signals self.clkbuf = factory.create(module_type="pdriver", fanout=clock_fanout, height=dff_height) diff --git a/compiler/pgates/pand2.py b/compiler/pgates/pand2.py index 2d04eb34..a5805728 100644 --- a/compiler/pgates/pand2.py +++ b/compiler/pgates/pand2.py @@ -15,7 +15,7 @@ class pand2(pgate.pgate): pgate.pgate.__init__(self, name, height) debug.info(1, "Creating {}".format(self.name)) - + self.add_comment("size: {}".format(size)) self.create_netlist() if not OPTS.netlist_only: diff --git a/compiler/pgates/pbuf.py b/compiler/pgates/pbuf.py index 3789ffc2..a0b36111 100644 --- a/compiler/pgates/pbuf.py +++ b/compiler/pgates/pbuf.py @@ -18,7 +18,8 @@ class pbuf(pgate.pgate): pgate.pgate.__init__(self, name, height) debug.info(1, "creating {0} with size of {1}".format(self.name,self.size)) - + self.add_comment("size: {}".format(size)) + self.create_netlist() if not OPTS.netlist_only: self.create_layout() diff --git a/compiler/pgates/pdriver.py b/compiler/pgates/pdriver.py index 4f440261..cb14c867 100644 --- a/compiler/pgates/pdriver.py +++ b/compiler/pgates/pdriver.py @@ -13,7 +13,7 @@ class pdriver(pgate.pgate): """ def __init__(self, name, neg_polarity=False, fanout=0, size_list=None, height=None): - self.stage_effort = 4 + self.stage_effort = 3 self.height = height self.neg_polarity = neg_polarity self.size_list = size_list @@ -27,6 +27,8 @@ class pdriver(pgate.pgate): self.compute_sizes() + self.add_comment("sizes: {}".format(str(self.size_list))) + self.create_netlist() if not OPTS.netlist_only: self.create_layout() diff --git a/compiler/pgates/pinv.py b/compiler/pgates/pinv.py index ac850d76..aa16ab54 100644 --- a/compiler/pgates/pinv.py +++ b/compiler/pgates/pinv.py @@ -26,6 +26,7 @@ class pinv(pgate.pgate): # have poly connected, for example. pgate.pgate.__init__(self, name, height) debug.info(2, "create pinv structure {0} with size of {1}".format(name, size)) + self.add_comment("size: {}".format(size)) self.size = size self.nmos_size = size diff --git a/compiler/pgates/pinvbuf.py b/compiler/pgates/pinvbuf.py index 3be4d7f1..e950bd3f 100644 --- a/compiler/pgates/pinvbuf.py +++ b/compiler/pgates/pinvbuf.py @@ -25,6 +25,7 @@ class pinvbuf(design.design): design.design.__init__(self, name) debug.info(1, "Creating {}".format(self.name)) + self.add_comment("size: {}".format(size)) self.create_netlist() if not OPTS.netlist_only: diff --git a/compiler/pgates/pnand2.py b/compiler/pgates/pnand2.py index 1ce87750..d196bf15 100644 --- a/compiler/pgates/pnand2.py +++ b/compiler/pgates/pnand2.py @@ -16,6 +16,7 @@ class pnand2(pgate.pgate): """ Creates a cell for a simple 2 input nand """ pgate.pgate.__init__(self, name, height) debug.info(2, "create pnand2 structure {0} with size of {1}".format(name, size)) + self.add_comment("size: {}".format(size)) self.size = size self.nmos_size = 2*size diff --git a/compiler/pgates/pnand3.py b/compiler/pgates/pnand3.py index cedf161f..29ae98c0 100644 --- a/compiler/pgates/pnand3.py +++ b/compiler/pgates/pnand3.py @@ -15,6 +15,7 @@ class pnand3(pgate.pgate): """ Creates a cell for a simple 3 input nand """ pgate.pgate.__init__(self, name, height) debug.info(2, "create pnand3 structure {0} with size of {1}".format(name, size)) + self.add_comment("size: {}".format(size)) # We have trouble pitch matching a 3x sizes to the bitcell... # If we relax this, we could size this better. diff --git a/compiler/pgates/pnor2.py b/compiler/pgates/pnor2.py index 93a0fd36..d1be51f3 100644 --- a/compiler/pgates/pnor2.py +++ b/compiler/pgates/pnor2.py @@ -15,6 +15,7 @@ class pnor2(pgate.pgate): """ Creates a cell for a simple 2 input nor """ pgate.pgate.__init__(self, name, height) debug.info(2, "create pnor2 structure {0} with size of {1}".format(name, size)) + self.add_comment("size: {}".format(size)) self.nmos_size = size # We will just make this 1.5 times for now. NORs are not ideal anyhow. From 8f56953af0e79c41bc819bd5fd28c8ea6b025dc9 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Thu, 24 Jan 2019 10:20:23 -0800 Subject: [PATCH 27/44] Convert wordline driver to use sized pdriver --- compiler/modules/bank.py | 3 ++- compiler/modules/wordline_driver.py | 7 +++++-- compiler/tests/08_wordline_driver_test.py | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index fc00e1c4..a7e78980 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -446,7 +446,8 @@ class bank(design.design): self.add_mod(self.row_decoder) self.wordline_driver = factory.create(module_type="wordline_driver", - rows=self.num_rows) + rows=self.num_rows, + cols=self.num_cols) self.add_mod(self.wordline_driver) self.inv = factory.create(module_type="pinv") diff --git a/compiler/modules/wordline_driver.py b/compiler/modules/wordline_driver.py index 72f73a57..9b3d319c 100644 --- a/compiler/modules/wordline_driver.py +++ b/compiler/modules/wordline_driver.py @@ -15,10 +15,11 @@ class wordline_driver(design.design): Generates the wordline-driver to drive the bitcell """ - def __init__(self, name, rows): + def __init__(self, name, rows, cols): design.design.__init__(self, name) self.rows = rows + self.cols = cols self.create_netlist() if not OPTS.netlist_only: @@ -52,7 +53,9 @@ class wordline_driver(design.design): # This is just used for measurements, # so don't add the module - self.inv = factory.create(module_type="pinv") + self.inv = factory.create(module_type="pdriver", + fanout=self.cols, + neg_polarity=True) self.add_mod(self.inv) self.inv_no_output = factory.create(module_type="pinv", diff --git a/compiler/tests/08_wordline_driver_test.py b/compiler/tests/08_wordline_driver_test.py index bfbf54d8..bc69c776 100755 --- a/compiler/tests/08_wordline_driver_test.py +++ b/compiler/tests/08_wordline_driver_test.py @@ -22,7 +22,7 @@ class wordline_driver_test(openram_test): # check wordline driver for single port debug.info(2, "Checking driver") - tx = wordline_driver.wordline_driver(name="wld1", rows=8) + tx = wordline_driver.wordline_driver(name="wld1", rows=8, cols=32) self.local_check(tx) # check wordline driver for multi-port @@ -33,7 +33,7 @@ class wordline_driver_test(openram_test): factory.reset() debug.info(2, "Checking driver (multi-port case)") - tx = wordline_driver.wordline_driver(name="wld2", rows=8) + tx = wordline_driver.wordline_driver(name="wld2", rows=8, cols=64) self.local_check(tx) globals.end_openram() From ddf734891a96938fd684854de18d5bded9b2bedc Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Fri, 25 Jan 2019 10:26:31 -0800 Subject: [PATCH 28/44] Fix pdriver width error --- compiler/modules/control_logic.py | 4 +++- compiler/modules/wordline_driver.py | 4 ++-- compiler/pgates/pdriver.py | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index 594ebd2c..495b8ada 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -86,7 +86,9 @@ class control_logic(design.design): # Special gates: inverters for buffering # clk_buf drives a flop for every address and control bit - clock_fanout = math.log(self.num_words,2) + math.log(self.words_per_row,2)+1 + self.num_control_signals + # plus about 5 fanouts for the control logic + clock_fanout = math.log(self.num_words,2) + math.log(self.words_per_row,2) \ + + self.num_control_signals + 5 self.clkbuf = factory.create(module_type="pdriver", fanout=clock_fanout, height=dff_height) diff --git a/compiler/modules/wordline_driver.py b/compiler/modules/wordline_driver.py index 9b3d319c..7907247b 100644 --- a/compiler/modules/wordline_driver.py +++ b/compiler/modules/wordline_driver.py @@ -231,8 +231,8 @@ class wordline_driver(design.design): stage_effort_list.append(stage1) last_stage_is_rise = stage1.is_rise - stage2 = self.inv.get_stage_effort(external_cout, last_stage_is_rise) - stage_effort_list.append(stage2) + stage2 = self.inv.get_stage_efforts(external_cout, last_stage_is_rise) + stage_effort_list.extend(stage2) return stage_effort_list diff --git a/compiler/pgates/pdriver.py b/compiler/pgates/pdriver.py index cb14c867..7b3283e7 100644 --- a/compiler/pgates/pdriver.py +++ b/compiler/pgates/pdriver.py @@ -100,8 +100,8 @@ class pdriver(pgate.pgate): self.create_insts() def create_layout(self): - self.width = self.num_inv * self.inv_list[0].width - self.height = self.inv_list[0].height + self.width = self.inv_inst_list[-1].rx() + self.height = self.inv_inst_list[0].uy() self.place_modules() self.route_wires() From 614aa54f179fe553cb9fdd48dfeda5618a832abe Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Fri, 25 Jan 2019 14:03:52 -0800 Subject: [PATCH 29/44] Move clkbuf output lower to avoid dff outputs --- compiler/modules/control_logic.py | 30 ++++++++++++++++-------------- compiler/pgates/pdriver.py | 2 +- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index 495b8ada..b5f8096a 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -89,11 +89,11 @@ class control_logic(design.design): # plus about 5 fanouts for the control logic clock_fanout = math.log(self.num_words,2) + math.log(self.words_per_row,2) \ + self.num_control_signals + 5 - self.clkbuf = factory.create(module_type="pdriver", - fanout=clock_fanout, - height=dff_height) + self.clk_buf_driver = factory.create(module_type="pdriver", + fanout=clock_fanout, + height=dff_height) - self.add_mod(self.clkbuf) + self.add_mod(self.clk_buf_driver) # wl_en drives every row in the bank self.wl_en_driver = factory.create(module_type="pdriver", @@ -415,8 +415,8 @@ class control_logic(design.design): def create_clk_buf_row(self): """ Create the multistage and gated clock buffer """ - self.clkbuf_inst = self.add_inst(name="clkbuf", - mod=self.clkbuf) + self.clk_buf_inst = self.add_inst(name="clkbuf", + mod=self.clk_buf_driver) self.connect_inst(["clk","clk_buf","vdd","gnd"]) def place_clk_buf_row(self,row): @@ -425,12 +425,12 @@ class control_logic(design.design): (y_off,mirror)=self.get_offset(row) offset = vector(x_off,y_off) - self.clkbuf_inst.place(offset, mirror) + self.clk_buf_inst.place(offset, mirror) - self.row_end_inst.append(self.clkbuf_inst) + self.row_end_inst.append(self.clk_buf_inst) def route_clk_buf(self): - clk_pin = self.clkbuf_inst.get_pin("A") + clk_pin = self.clk_buf_inst.get_pin("A") clk_pos = clk_pin.center() self.add_layout_pin_segment_center(text="clk", layer="metal2", @@ -440,14 +440,16 @@ class control_logic(design.design): offset=clk_pos) - clkbuf_map = zip(["Z"], ["clk_buf"]) - self.connect_vertical_bus(clkbuf_map, self.clkbuf_inst, self.rail_offsets, ("metal3", "via2", "metal2")) + # Connect this at the bottom of the buffer + out_pos = self.clk_buf_inst.get_pin("Z").center() + mid1 = vector(out_pos.x,2*self.m2_pitch) + bus_pos = vector(self.rail_offsets["clk_buf"].x, mid1.y) + self.add_wire(("metal3","via2","metal2"),[out_pos, mid1, bus_pos]) # The pin is on M1, so we need another via as well self.add_via_center(layers=("metal1","via1","metal2"), - offset=self.clkbuf_inst.get_pin("Z").center()) - + offset=self.clk_buf_inst.get_pin("Z").center()) - self.connect_output(self.clkbuf_inst, "Z", "clk_buf") + self.connect_output(self.clk_buf_inst, "Z", "clk_buf") def create_gated_clk_bar_row(self): self.clk_bar_inst = self.add_inst(name="inv_clk_bar", diff --git a/compiler/pgates/pdriver.py b/compiler/pgates/pdriver.py index 7b3283e7..cc5e77f4 100644 --- a/compiler/pgates/pdriver.py +++ b/compiler/pgates/pdriver.py @@ -101,7 +101,7 @@ class pdriver(pgate.pgate): def create_layout(self): self.width = self.inv_inst_list[-1].rx() - self.height = self.inv_inst_list[0].uy() + self.height = self.inv_inst_list[0].height self.place_modules() self.route_wires() From 6f32bac1a243bcbd7f7d14cee64eebc7b2baf237 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Fri, 25 Jan 2019 14:17:37 -0800 Subject: [PATCH 30/44] Use rx of last pdriver instance after placing instances --- compiler/modules/control_logic.py | 5 +++-- compiler/pgates/pdriver.py | 12 ++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index b5f8096a..676927b5 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -443,8 +443,9 @@ class control_logic(design.design): # Connect this at the bottom of the buffer out_pos = self.clk_buf_inst.get_pin("Z").center() mid1 = vector(out_pos.x,2*self.m2_pitch) - bus_pos = vector(self.rail_offsets["clk_buf"].x, mid1.y) - self.add_wire(("metal3","via2","metal2"),[out_pos, mid1, bus_pos]) + mid2 = vector(self.rail_offsets["clk_buf"].x, mid1.y) + bus_pos = self.rail_offsets["clk_buf"] + self.add_wire(("metal3","via2","metal2"),[out_pos, mid1, mid2, bus_pos]) # The pin is on M1, so we need another via as well self.add_via_center(layers=("metal1","via1","metal2"), offset=self.clk_buf_inst.get_pin("Z").center()) diff --git a/compiler/pgates/pdriver.py b/compiler/pgates/pdriver.py index cc5e77f4..b4491cb8 100644 --- a/compiler/pgates/pdriver.py +++ b/compiler/pgates/pdriver.py @@ -100,13 +100,13 @@ class pdriver(pgate.pgate): self.create_insts() def create_layout(self): - self.width = self.inv_inst_list[-1].rx() - self.height = self.inv_inst_list[0].height - self.place_modules() self.route_wires() self.add_layout_pins() - + + self.width = self.inv_inst_list[-1].rx() + self.height = self.inv_inst_list[0].height + self.DRC_LVS() def add_pins(self): @@ -153,10 +153,10 @@ class pdriver(pgate.pgate): def place_modules(self): - # Add INV1 to the left + # Add the first inverter at the origin self.inv_inst_list[0].place(vector(0,0)) - # Add inverters to the right of INV1 + # Add inverters to the right of the previous inverter for x in range(1,len(self.inv_inst_list)): self.inv_inst_list[x].place(vector(self.inv_inst_list[x-1].rx(),0)) From 1afd4341bdf2fc3945eb8ff670e69741322a8fc3 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Fri, 25 Jan 2019 14:22:37 -0800 Subject: [PATCH 31/44] Update stage effort of clk_buf_driver --- compiler/modules/control_logic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index 676927b5..781402de 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -833,7 +833,7 @@ class control_logic(design.design): #Calculate the load on wl_en within the module and add it to external load external_cout = self.sram.get_wl_en_cin() #First stage is the clock buffer - stage_effort_list += self.clkbuf.get_stage_efforts(external_cout, is_clk_bar_rise) + stage_effort_list += self.clk_buf_driver.get_stage_efforts(external_cout, is_clk_bar_rise) last_stage_is_rise = stage_effort_list[-1].is_rise #Then ask the sram for the other path delays (from the bank) From 0c3baa51728fa7c742c701a7968bab5c2fbeb899 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Fri, 25 Jan 2019 15:00:00 -0800 Subject: [PATCH 32/44] Added some comments to the spice files. --- compiler/modules/bitcell_array.py | 2 +- compiler/modules/control_logic.py | 3 +++ compiler/modules/delay_chain.py | 4 +++- compiler/modules/dff_array.py | 5 +++-- compiler/modules/dff_buf.py | 3 ++- compiler/modules/dff_buf_array.py | 3 +++ compiler/modules/dff_inv.py | 2 ++ compiler/modules/dff_inv_array.py | 3 +++ compiler/modules/precharge_array.py | 3 ++- compiler/modules/sense_amp_array.py | 2 ++ compiler/modules/single_level_column_mux_array.py | 2 ++ compiler/modules/wordline_driver.py | 4 +++- compiler/modules/write_driver_array.py | 2 ++ compiler/sram_factory.py | 4 ++-- 14 files changed, 33 insertions(+), 9 deletions(-) diff --git a/compiler/modules/bitcell_array.py b/compiler/modules/bitcell_array.py index 166437fa..67e5a9da 100644 --- a/compiler/modules/bitcell_array.py +++ b/compiler/modules/bitcell_array.py @@ -14,7 +14,7 @@ class bitcell_array(design.design): def __init__(self, cols, rows, name): design.design.__init__(self, name) debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols)) - + self.add_comment("rows: {0} cols: {1}".format(rows, cols)) self.column_size = cols self.row_size = rows diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index 781402de..805cbea9 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -19,6 +19,9 @@ class control_logic(design.design): name = "control_logic_" + port_type design.design.__init__(self, name) debug.info(1, "Creating {}".format(name)) + self.add_comment("num_rows: {0}".format(num_rows)) + self.add_comment("words_per_row: {0}".format(words_per_row)) + self.add_comment("word_size {0}".format(word_size)) self.sram=sram self.num_rows = num_rows diff --git a/compiler/modules/delay_chain.py b/compiler/modules/delay_chain.py index 848e4e85..f3d15ba3 100644 --- a/compiler/modules/delay_chain.py +++ b/compiler/modules/delay_chain.py @@ -16,7 +16,9 @@ class delay_chain(design.design): def __init__(self, name, fanout_list): """init function""" design.design.__init__(self, name) - + debug.info(1, "creating delay chain {0}".format(str(fanout_list))) + self.add_comment("fanouts: {0}".format(str(fanout_list))) + # Two fanouts are needed so that we can route the vdd/gnd connections for f in fanout_list: debug.check(f>=2,"Must have >=2 fanouts for each stage.") diff --git a/compiler/modules/dff_array.py b/compiler/modules/dff_array.py index 215d2884..5d728205 100644 --- a/compiler/modules/dff_array.py +++ b/compiler/modules/dff_array.py @@ -12,7 +12,7 @@ class dff_array(design.design): Unlike the data flops, these are never spaced out. """ - def __init__(self, rows, columns, inv1_size=2, inv2_size=4, name=""): + def __init__(self, rows, columns, name=""): self.rows = rows self.columns = columns @@ -20,7 +20,8 @@ class dff_array(design.design): name = "dff_array_{0}x{1}".format(rows, columns) design.design.__init__(self, name) debug.info(1, "Creating {0} rows={1} cols={2}".format(self.name, self.rows, self.columns)) - + self.add_comment("rows: {0} cols: {1}".format(rows, columns)) + self.create_netlist() if not OPTS.netlist_only: self.create_layout() diff --git a/compiler/modules/dff_buf.py b/compiler/modules/dff_buf.py index 4f6fff11..42d37bd1 100644 --- a/compiler/modules/dff_buf.py +++ b/compiler/modules/dff_buf.py @@ -21,7 +21,8 @@ class dff_buf(design.design): dff_buf.unique_id += 1 design.design.__init__(self, name) debug.info(1, "Creating {}".format(self.name)) - + self.add_comment("inv1: {0} inv2: {1}".format(inv1_size, inv2_size)) + # This is specifically for SCMOS where the DFF vdd/gnd rails are more than min width. # This causes a DRC in the pinv which assumes min width rails. This ensures the output # contact does not violate spacing to the rail in the NMOS. diff --git a/compiler/modules/dff_buf_array.py b/compiler/modules/dff_buf_array.py index 4d655a64..b179b1c3 100644 --- a/compiler/modules/dff_buf_array.py +++ b/compiler/modules/dff_buf_array.py @@ -22,6 +22,9 @@ class dff_buf_array(design.design): dff_buf_array.unique_id += 1 design.design.__init__(self, name) debug.info(1, "Creating {}".format(self.name)) + self.add_comment("rows: {0} cols: {1}".format(rows, columns)) + self.add_comment("inv1: {0} inv2: {1}".format(inv1_size, inv2_size)) + self.inv1_size = inv1_size self.inv2_size = inv2_size diff --git a/compiler/modules/dff_inv.py b/compiler/modules/dff_inv.py index f8ff00bf..436026bb 100644 --- a/compiler/modules/dff_inv.py +++ b/compiler/modules/dff_inv.py @@ -20,6 +20,8 @@ class dff_inv(design.design): dff_inv.unique_id += 1 design.design.__init__(self, name) debug.info(1, "Creating {}".format(self.name)) + self.add_comment("inv: {0}".format(inv_size)) + self.inv_size = inv_size # This is specifically for SCMOS where the DFF vdd/gnd rails are more than min width. diff --git a/compiler/modules/dff_inv_array.py b/compiler/modules/dff_inv_array.py index 629a1d67..91ccfa92 100644 --- a/compiler/modules/dff_inv_array.py +++ b/compiler/modules/dff_inv_array.py @@ -22,6 +22,9 @@ class dff_inv_array(design.design): dff_inv_array.unique_id += 1 design.design.__init__(self, name) debug.info(1, "Creating {}".format(self.name)) + self.add_comment("rows: {0} cols: {1}".format(rows, columns)) + self.add_comment("inv1: {0}".format(inv1_size)) + self.inv_size = inv_size self.create_netlist() diff --git a/compiler/modules/precharge_array.py b/compiler/modules/precharge_array.py index ff84cfe6..67581e1a 100644 --- a/compiler/modules/precharge_array.py +++ b/compiler/modules/precharge_array.py @@ -14,7 +14,8 @@ class precharge_array(design.design): def __init__(self, name, columns, size=1, bitcell_bl="bl", bitcell_br="br"): design.design.__init__(self, name) debug.info(1, "Creating {0}".format(self.name)) - + self.add_comment("cols: {0} size: {1} bl: {2} br: {3}".format(columns, size, bitcell_bl, bitcell_br)) + self.columns = columns self.size = size self.bitcell_bl = bitcell_bl diff --git a/compiler/modules/sense_amp_array.py b/compiler/modules/sense_amp_array.py index 3209377b..ebf95c95 100644 --- a/compiler/modules/sense_amp_array.py +++ b/compiler/modules/sense_amp_array.py @@ -14,6 +14,8 @@ class sense_amp_array(design.design): def __init__(self, name, word_size, words_per_row): design.design.__init__(self, name) debug.info(1, "Creating {0}".format(self.name)) + self.add_comment("word_size {0}".format(word_size)) + self.add_comment("words_per_row: {0}".format(words_per_row)) self.word_size = word_size self.words_per_row = words_per_row diff --git a/compiler/modules/single_level_column_mux_array.py b/compiler/modules/single_level_column_mux_array.py index 9ce95c66..49293568 100644 --- a/compiler/modules/single_level_column_mux_array.py +++ b/compiler/modules/single_level_column_mux_array.py @@ -17,6 +17,8 @@ class single_level_column_mux_array(design.design): def __init__(self, name, columns, word_size, bitcell_bl="bl", bitcell_br="br"): design.design.__init__(self, name) debug.info(1, "Creating {0}".format(self.name)) + self.add_comment("cols: {0} word_size: {1} bl: {2} br: {3}".format(columns, word_size, bitcell_bl, bitcell_br)) + self.columns = columns self.word_size = word_size self.words_per_row = int(self.columns / self.word_size) diff --git a/compiler/modules/wordline_driver.py b/compiler/modules/wordline_driver.py index 7907247b..830c28de 100644 --- a/compiler/modules/wordline_driver.py +++ b/compiler/modules/wordline_driver.py @@ -17,7 +17,9 @@ class wordline_driver(design.design): def __init__(self, name, rows, cols): design.design.__init__(self, name) - + debug.info(1, "Creating {0}".format(self.name)) + self.add_comment("rows: {0} cols: {1}".format(rows, cols)) + self.rows = rows self.cols = cols diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index 76eb9f84..3367cc00 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -15,6 +15,8 @@ class write_driver_array(design.design): def __init__(self, name, columns, word_size): design.design.__init__(self, name) debug.info(1, "Creating {0}".format(self.name)) + self.add_comment("columns: {0}".format(columns)) + self.add_comment("word_size {0}".format(word_size)) self.columns = columns self.word_size = word_size diff --git a/compiler/sram_factory.py b/compiler/sram_factory.py index 21aa7027..7b420a6b 100644 --- a/compiler/sram_factory.py +++ b/compiler/sram_factory.py @@ -58,7 +58,7 @@ class sram_factory: (obj_kwargs, obj_item) = obj # Must have the same dictionary exactly (conservative) if obj_kwargs == kwargs: - debug.info(1, "Existing module: type={0} name={1} kwargs={2}".format(module_type, obj_item.name, str(kwargs))) + #debug.info(1, "Existing module: type={0} name={1} kwargs={2}".format(module_type, obj_item.name, str(kwargs))) return obj_item # Use the default name if there are default arguments @@ -67,7 +67,7 @@ class sram_factory: # Create a unique name and increment the index module_name = "{0}_{1}".format(module_name, self.module_indices[module_type]) self.module_indices[module_type] += 1 - debug.info(1, "New module: type={0} name={1} kwargs={2}".format(module_type,module_name,str(kwargs))) + #debug.info(1, "New module: type={0} name={1} kwargs={2}".format(module_type,module_name,str(kwargs))) obj = mod(name=module_name,**kwargs) self.objects[module_type].append((kwargs,obj)) return obj From 09d6a63861b2b34776a889dae5fb4e1083e8fb2b Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Fri, 25 Jan 2019 15:07:56 -0800 Subject: [PATCH 33/44] Change path to wire_path for Anaconda package conflict --- compiler/base/hierarchy_layout.py | 10 +++++----- compiler/base/wire.py | 6 +++--- compiler/base/{path.py => wire_path.py} | 12 ++++++------ compiler/pgates/ptx.py | 1 - compiler/tests/03_path_test.py | 10 +++++----- 5 files changed, 19 insertions(+), 20 deletions(-) rename compiler/base/{path.py => wire_path.py} (94%) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 60a596bb..7c998176 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -320,17 +320,17 @@ class layout(): def add_path(self, layer, coordinates, width=None): """Connects a routing path on given layer,coordinates,width.""" debug.info(4,"add path " + str(layer) + " " + str(coordinates)) - import path + import wire_path # NOTE: (UNTESTED) add_path(...) is currently not used # negative layers indicate "unused" layers in a given technology #layer_num = techlayer[layer] #if layer_num >= 0: # self.objs.append(geometry.path(layer_num, coordinates, width)) - path.path(obj=self, - layer=layer, - position_list=coordinates, - width=width) + wire_path.wire_path(obj=self, + layer=layer, + position_list=coordinates, + width=width) def add_route(self, layers, coordinates, layer_widths): """Connects a routing path on given layer,coordinates,width. The diff --git a/compiler/base/wire.py b/compiler/base/wire.py index 8500e502..8bc250fa 100644 --- a/compiler/base/wire.py +++ b/compiler/base/wire.py @@ -1,9 +1,9 @@ from tech import drc import debug -from path import path +from wire_path import wire_path from sram_factory import factory -class wire(path): +class wire(wire_path): """ Object metal wire; given the layer type Add a wire of minimium metal width between a set of points. @@ -26,7 +26,7 @@ class wire(path): self.create_rectilinear() self.create_vias() self.create_rectangles() - # wires and paths should not be offset to (0,0) + # wires and wire_paths should not be offset to (0,0) def setup_layers(self): (horiz_layer, via_layer, vert_layer) = self.layer_stack diff --git a/compiler/base/path.py b/compiler/base/wire_path.py similarity index 94% rename from compiler/base/path.py rename to compiler/base/wire_path.py index ed058fef..ec5d01bf 100644 --- a/compiler/base/path.py +++ b/compiler/base/wire_path.py @@ -18,12 +18,12 @@ def create_rectilinear_route(my_list): my_list.append(vector(pl[-1])) return my_list -class path(): +class wire_path(): """ - Object metal path; given the layer type - Add a path of minimium metal width between a set of points. + Object metal wire_path; given the layer type + Add a wire_path of minimium metal width between a set of points. The points should be rectilinear to control the bend points. If - not, it will always go down first. The points are the center of the path. + not, it will always go down first. The points are the center of the wire_path. If width is not given, it uses minimum layer width. """ def __init__(self, obj, layer, position_list, width=None): @@ -44,7 +44,7 @@ class path(): self.create_rectilinear() self.connect_corner() self.create_rectangles() - # wires and paths should not be offset to (0,0) + # wires and wire_paths should not be offset to (0,0) def create_rectilinear(self): """ Add intermediate nodes if it isn't rectilinear. Also skip @@ -52,7 +52,7 @@ class path(): self.position_list = create_rectilinear_route(self.position_list) def connect_corner(self): - """ Add a corner square at every corner of the path.""" + """ Add a corner square at every corner of the wire_path.""" from itertools import tee,islice nwise = lambda g,n=2: zip(*(islice(g,i,None) for i,g in enumerate(tee(g,n)))) threewise=nwise(self.position_list,3) diff --git a/compiler/pgates/ptx.py b/compiler/pgates/ptx.py index 3d7ce296..3a127454 100644 --- a/compiler/pgates/ptx.py +++ b/compiler/pgates/ptx.py @@ -3,7 +3,6 @@ import debug from tech import drc, spice from vector import vector from globals import OPTS -import path from sram_factory import factory class ptx(design.design): diff --git a/compiler/tests/03_path_test.py b/compiler/tests/03_path_test.py index 915c5c78..f0fc2299 100755 --- a/compiler/tests/03_path_test.py +++ b/compiler/tests/03_path_test.py @@ -13,7 +13,7 @@ class path_test(openram_test): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) - import path + import wire_path import tech import design @@ -27,7 +27,7 @@ class path_test(openram_test): [0, 3 * min_space ], [0, 6 * min_space ]] w = design.design("path_test0") - path.path(w,layer_stack, position_list) + wire_path.wire_path(w,layer_stack, position_list) self.local_drc_check(w) @@ -44,7 +44,7 @@ class path_test(openram_test): [-1 * min_space, 0]] position_list = [[x+min_space, y+min_space] for x,y in old_position_list] w = design.design("path_test1") - path.path(w,layer_stack, position_list) + wire_path.wire_path(w,layer_stack, position_list) self.local_drc_check(w) min_space = 2 * tech.drc["minwidth_metal2"] @@ -60,7 +60,7 @@ class path_test(openram_test): [-1 * min_space, 0]] position_list = [[x-min_space, y-min_space] for x,y in old_position_list] w = design.design("path_test2") - path.path(w, layer_stack, position_list) + wire_path.wire_path(w, layer_stack, position_list) self.local_drc_check(w) min_space = 2 * tech.drc["minwidth_metal3"] @@ -77,7 +77,7 @@ class path_test(openram_test): # run on the reverse list position_list.reverse() w = design.design("path_test3") - path.path(w, layer_stack, position_list) + wire_path.wire_path(w, layer_stack, position_list) self.local_drc_check(w) globals.end_openram() From d2864370aac4ac838dda3c97f1aadb9ca91f2b48 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Fri, 25 Jan 2019 15:43:57 -0800 Subject: [PATCH 34/44] Temporarily disable abort on supply error --- compiler/verify/calibre.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/verify/calibre.py b/compiler/verify/calibre.py index 7510b340..4eb05448 100644 --- a/compiler/verify/calibre.py +++ b/compiler/verify/calibre.py @@ -183,7 +183,9 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False): #'lvsAbortOnSupplyError' : 0 # This should be removed for final verification - if not final_verification: + # FIXMEFIXMEFIXME + # MRG: Just doing this to merge pdriver + if True or not final_verification: lvs_runset['cmnVConnectReport']=1 lvs_runset['cmnVConnectNamesState']='SOME' lvs_runset['cmnVConnectNames']='vdd gnd' From c286879a289933508b4a614da53680e5f9216d59 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Fri, 25 Jan 2019 15:47:09 -0800 Subject: [PATCH 35/44] Minor edits to README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5c4ae3c5..f70a2d87 100644 --- a/README.md +++ b/README.md @@ -133,7 +133,7 @@ To increase the verbosity of the test, add one (or more) -v options: python3 tests/00_code_format_check_test.py -v -t freepdk45 ``` To specify a particular technology use "-t " such as -"-t freepdk45" or "-t scn4m\_subm". The default for a unit test is scn4m_subm. +"-t freepdk45". The default for a unit test is scn4m_subm. The default for openram.py is specified in the configuration file. @@ -164,7 +164,7 @@ Each specific technology (e.g., [FreePDK45]) should be a subdirectory * replica\_cell\_6t.gds * sp_lib folder with all the .sp (premade) library netlists for the above cells. * layers.map -* A valid tech Python module (tech directory with __init__.py and tech.py) with: +* A valid tech Python module (tech directory with \_\_init\_\_.py and tech.py) with: * References in tech.py to spice models * DRC/LVS rules needed for dynamic cells and routing * Layer information From 01ab253925b107a778fbe2fbe9b086bef4e2dbb3 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Fri, 25 Jan 2019 15:56:12 -0800 Subject: [PATCH 36/44] Move gdsMill license to README --- compiler/gdsMill/LICENSE | 78 ------------------------------- compiler/gdsMill/README | 99 ++++++++++++++++++++++++++++++---------- 2 files changed, 75 insertions(+), 102 deletions(-) delete mode 100644 compiler/gdsMill/LICENSE diff --git a/compiler/gdsMill/LICENSE b/compiler/gdsMill/LICENSE deleted file mode 100644 index 6d8a8921..00000000 --- a/compiler/gdsMill/LICENSE +++ /dev/null @@ -1,78 +0,0 @@ -Delivered-To: mrg@ucsc.edu -Received: by 10.216.164.197 with SMTP id c47cs36474wel; - Sat, 19 Nov 2011 21:23:28 -0800 (PST) -Received: by 10.216.133.5 with SMTP id p5mr1106280wei.105.1321766513080; - Sat, 19 Nov 2011 21:21:53 -0800 (PST) -Received-SPF: softfail (google.com: best guess record for domain of transitioning wieckows@umich.edu does not designate 128.114.48.32 as permitted sender) client-ip=128.114.48.32; -Received: by 10.241.242.69 with POP3 id 5mf3470160wwf.5; - Sat, 19 Nov 2011 21:21:53 -0800 (PST) -X-Gmail-Fetch-Info: mguthaus@gmail.com 1 smtp.gmail.com 995 mguthaus -Delivered-To: mguthaus@gmail.com -Received: by 10.231.207.15 with SMTP id fw15cs52829ibb; - Thu, 14 Oct 2010 12:49:35 -0700 (PDT) -Received: by 10.142.224.8 with SMTP id w8mr3585480wfg.123.1287085774723; - Thu, 14 Oct 2010 12:49:34 -0700 (PDT) -Return-Path: -Received: from mail-01.cse.ucsc.edu (mail-01.cse.ucsc.edu [128.114.48.32]) - by mx.google.com with ESMTP id x31si25240170wfd.118.2010.10.14.12.49.34; - Thu, 14 Oct 2010 12:49:34 -0700 (PDT) -Received-SPF: neutral (google.com: 128.114.48.32 is neither permitted nor denied by best guess record for domain of wieckows@umich.edu) client-ip=128.114.48.32; -Authentication-Results: mx.google.com; spf=neutral (google.com: 128.114.48.32 is neither permitted nor denied by best guess record for domain of wieckows@umich.edu) smtp.mail=wieckows@umich.edu -Received: from services.cse.ucsc.edu (services.cse.ucsc.edu [128.114.48.10]) - by mail-01.cse.ucsc.edu (Postfix) with ESMTP id 60660100985C - for ; Thu, 14 Oct 2010 12:49:34 -0700 (PDT) -Received: from mailgw.soe.ucsc.edu (mailgw.cse.ucsc.edu [128.114.48.9]) - by services.cse.ucsc.edu (8.13.6/8.13.6) with ESMTP id o9EJnXcg026705 - (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) - for ; Thu, 14 Oct 2010 12:49:34 -0700 (PDT) -X-ASG-Debug-ID: 1287085773-35c0a0820001-k66d7V -Received: from hellskitchen.mr.itd.umich.edu (smtp.mail.umich.edu [141.211.14.82]) by mailgw.soe.ucsc.edu with ESMTP id iCFqYJFhVj1wHPNy for ; Thu, 14 Oct 2010 12:49:33 -0700 (PDT) -X-Barracuda-Envelope-From: wieckows@umich.edu -X-Barracuda-Apparent-Source-IP: 141.211.14.82 -Received: FROM [10.0.1.4] (adsl-99-67-97-169.dsl.sfldmi.sbcglobal.net [99.67.97.169]) - By hellskitchen.mr.itd.umich.edu ID 4CB75ECA.5F7DC.12653 ; - Authuser wieckows; - 14 Oct 2010 15:49:30 EDT -Content-Type: text/plain; charset=us-ascii -Mime-Version: 1.0 (Apple Message framework v1081) -Subject: Re: GDS Mill -From: Michael Wieckowski -X-ASG-Orig-Subj: Re: GDS Mill -In-Reply-To: -Date: Thu, 14 Oct 2010 15:49:29 -0400 -Content-Transfer-Encoding: quoted-printable -Message-Id: <7C1B8C49-7D87-4BF2-8ABF-6555CF7B37AD@umich.edu> -References: -To: Matthew Guthaus -X-Mailer: Apple Mail (2.1081) -X-Barracuda-Connect: smtp.mail.umich.edu[141.211.14.82] -X-Barracuda-Start-Time: 1287085773 -X-Barracuda-URL: http://mailgw.cse.ucsc.edu:8000/cgi-mod/mark.cgi -X-Virus-Scanned: by bsmtpd at soe.ucsc.edu - -Hi Matt, - -Feel free to use / modify / distribute the code as you like. - --Mike - - -On Oct 14, 2010, at 3:07 PM, Matthew Guthaus wrote: - -> Hi Michael (& Dennis), ->=20 -> A student and I were looking at your GDS tools, but we noticed that = -there is no license. What is the license? ->=20 -> Thanks, ->=20 -> Matt ->=20 -> --- -> Matthew Guthaus -> Assistant Professor, Computer Engineering -> University of California Santa Cruz -> http://vlsida.soe.ucsc.edu/ ->=20 ->=20 ->=20 diff --git a/compiler/gdsMill/README b/compiler/gdsMill/README index ce21dfdd..8d89b149 100644 --- a/compiler/gdsMill/README +++ b/compiler/gdsMill/README @@ -1,30 +1,81 @@ -README BY TOM GOLUBEV - gdsMill was adapted from gdsMill by Michael Wieckowski. -gdsMill allows one to work with GDS files, opening, reading, writing and altering. -It is a library and does not work by itself. To get started, refer to ExampleUserDir. -To look at sram compiler related example, refer to the sram_examples subdir. -gdsMill takes a layermap, in a standard format (virtuoso .map files). This is necessary -for drawing text and rectangles, since those functions take layernames, and gdsMill needs layer numbers. +Delivered-To: mrg@ucsc.edu +Received: by 10.216.164.197 with SMTP id c47cs36474wel; + Sat, 19 Nov 2011 21:23:28 -0800 (PST) +Received: by 10.216.133.5 with SMTP id p5mr1106280wei.105.1321766513080; + Sat, 19 Nov 2011 21:21:53 -0800 (PST) +Received-SPF: softfail (google.com: best guess record for domain of transitioning wieckows@umich.edu does not designate 128.114.48.32 as permitted sender) client-ip=128.114.48.32; +Received: by 10.241.242.69 with POP3 id 5mf3470160wwf.5; + Sat, 19 Nov 2011 21:21:53 -0800 (PST) +X-Gmail-Fetch-Info: mguthaus@gmail.com 1 smtp.gmail.com 995 mguthaus +Delivered-To: mguthaus@gmail.com +Received: by 10.231.207.15 with SMTP id fw15cs52829ibb; + Thu, 14 Oct 2010 12:49:35 -0700 (PDT) +Received: by 10.142.224.8 with SMTP id w8mr3585480wfg.123.1287085774723; + Thu, 14 Oct 2010 12:49:34 -0700 (PDT) +Return-Path: +Received: from mail-01.cse.ucsc.edu (mail-01.cse.ucsc.edu [128.114.48.32]) + by mx.google.com with ESMTP id x31si25240170wfd.118.2010.10.14.12.49.34; + Thu, 14 Oct 2010 12:49:34 -0700 (PDT) +Received-SPF: neutral (google.com: 128.114.48.32 is neither permitted nor denied by best guess record for domain of wieckows@umich.edu) client-ip=128.114.48.32; +Authentication-Results: mx.google.com; spf=neutral (google.com: 128.114.48.32 is neither permitted nor denied by best guess record for domain of wieckows@umich.edu) smtp.mail=wieckows@umich.edu +Received: from services.cse.ucsc.edu (services.cse.ucsc.edu [128.114.48.10]) + by mail-01.cse.ucsc.edu (Postfix) with ESMTP id 60660100985C + for ; Thu, 14 Oct 2010 12:49:34 -0700 (PDT) +Received: from mailgw.soe.ucsc.edu (mailgw.cse.ucsc.edu [128.114.48.9]) + by services.cse.ucsc.edu (8.13.6/8.13.6) with ESMTP id o9EJnXcg026705 + (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) + for ; Thu, 14 Oct 2010 12:49:34 -0700 (PDT) +X-ASG-Debug-ID: 1287085773-35c0a0820001-k66d7V +Received: from hellskitchen.mr.itd.umich.edu (smtp.mail.umich.edu [141.211.14.82]) by mailgw.soe.ucsc.edu with ESMTP id iCFqYJFhVj1wHPNy for ; Thu, 14 Oct 2010 12:49:33 -0700 (PDT) +X-Barracuda-Envelope-From: wieckows@umich.edu +X-Barracuda-Apparent-Source-IP: 141.211.14.82 +Received: FROM [10.0.1.4] (adsl-99-67-97-169.dsl.sfldmi.sbcglobal.net [99.67.97.169]) + By hellskitchen.mr.itd.umich.edu ID 4CB75ECA.5F7DC.12653 ; + Authuser wieckows; + 14 Oct 2010 15:49:30 EDT +Content-Type: text/plain; charset=us-ascii +Mime-Version: 1.0 (Apple Message framework v1081) +Subject: Re: GDS Mill +From: Michael Wieckowski +X-ASG-Orig-Subj: Re: GDS Mill +In-Reply-To: +Date: Thu, 14 Oct 2010 15:49:29 -0400 +Content-Transfer-Encoding: quoted-printable +Message-Id: <7C1B8C49-7D87-4BF2-8ABF-6555CF7B37AD@umich.edu> +References: +To: Matthew Guthaus +X-Mailer: Apple Mail (2.1081) +X-Barracuda-Connect: smtp.mail.umich.edu[141.211.14.82] +X-Barracuda-Start-Time: 1287085773 +X-Barracuda-URL: http://mailgw.cse.ucsc.edu:8000/cgi-mod/mark.cgi +X-Virus-Scanned: by bsmtpd at soe.ucsc.edu + +Hi Matt, + +Feel free to use / modify / distribute the code as you like. + +-Mike -gdsMill funcionality: +On Oct 14, 2010, at 3:07 PM, Matthew Guthaus wrote: -The main functions are from vlsilayout. They allow creating a new layout, fill in a box, text, and instancing other structures. - -Files: - - sram_examples: - - gdsMill.sh: Adds gdsMill to python path. - Source this before working - - printGDS.py: will dump a text version structures within the gds file. - usage: python printGDS.py file - - cell6tDemo.py: Will tile cell6t from sram_lib2.gds and output into layoutB.gds. All cells from source are copied into layoutB.gds. - usage: python ./cell6tDemo.py - - +> Hi Michael (& Dennis), +>=20 +> A student and I were looking at your GDS tools, but we noticed that = +there is no license. What is the license? +>=20 +> Thanks, +>=20 +> Matt +>=20 +> --- +> Matthew Guthaus +> Assistant Professor, Computer Engineering +> University of California Santa Cruz +> http://vlsida.soe.ucsc.edu/ +>=20 +>=20 +>=20 From be7384c01708265b6c7d6db652c06ef3276ab203 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Fri, 25 Jan 2019 15:58:49 -0800 Subject: [PATCH 37/44] Remove file named LICENSE since it is in the README for the tech files --- technology/scn3me_subm/tf/LICENSE | 4 ---- technology/scn4m_subm/tf/LICENSE | 4 ---- 2 files changed, 8 deletions(-) delete mode 100644 technology/scn3me_subm/tf/LICENSE delete mode 100644 technology/scn4m_subm/tf/LICENSE diff --git a/technology/scn3me_subm/tf/LICENSE b/technology/scn3me_subm/tf/LICENSE deleted file mode 100644 index 8d22c4be..00000000 --- a/technology/scn3me_subm/tf/LICENSE +++ /dev/null @@ -1,4 +0,0 @@ -The NCSU CDK is Copyright (C) NC State University, 1998, 1999, 2004, -2006. Users are free to use or modify the NCSU CDK as appropriate as long -as this notice appears in the modified package. The NCSU CDK is -provided with NO WARRANTY. diff --git a/technology/scn4m_subm/tf/LICENSE b/technology/scn4m_subm/tf/LICENSE deleted file mode 100644 index 8d22c4be..00000000 --- a/technology/scn4m_subm/tf/LICENSE +++ /dev/null @@ -1,4 +0,0 @@ -The NCSU CDK is Copyright (C) NC State University, 1998, 1999, 2004, -2006. Users are free to use or modify the NCSU CDK as appropriate as long -as this notice appears in the modified package. The NCSU CDK is -provided with NO WARRANTY. From beceb3fb6011671c98bd81f4a57aadb38d5232d2 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Fri, 25 Jan 2019 16:22:59 -0800 Subject: [PATCH 38/44] Fix buggy analytical delay in pdriver --- compiler/pgates/pdriver.py | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/compiler/pgates/pdriver.py b/compiler/pgates/pdriver.py index b4491cb8..c9f45473 100644 --- a/compiler/pgates/pdriver.py +++ b/compiler/pgates/pdriver.py @@ -203,22 +203,28 @@ class pdriver(pgate.pgate): width = a_pin.width(), height = a_pin.height()) + def input_load(self): + return self.inv_list[0].input_load() + def analytical_delay(self, slew, load=0.0): """Calculate the analytical delay of INV1 -> ... -> INVn""" - delay = 0; - if len(self.inv_inst_list) == 1: - delay = self.inv_inst_list[x].analytical_delay(slew=slew); - else: - for x in range(len(self.inv_inst_list-1)): - load_next = 0.0 - for n in range(x,len(self.inv_inst_list+1)): - load_next += self.inv_inst_list[x+1] - if x == 1: - delay += self.inv_inst_list[x].analytical_delay(slew=slew, - load=load_next) - else: - delay += self.inv_inst_list[x+1].analytical_delay(slew=delay.slew, - load=load_next) + + cout_list = [] + for prev_inv,inv in zip(self.inv_list, self.inv_list[1:]): + cout_list.append(inv.input_load()) + cout_list.append(load) + + input_slew = slew + + delays = [] + for inv,cout in zip(self.inv_list,cout_list): + delays.append(inv.analytical_delay(slew=input_slew, load=cout)) + input_slew = delays[-1].slew + + delay = delays[0] + for i in range(len(delays)-1): + delay += delays[i] + return delay From 18805423e32db50953673b31a5217192ce230499 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Fri, 25 Jan 2019 17:18:12 -0800 Subject: [PATCH 39/44] Simplify pdriver code. --- compiler/pgates/pdriver.py | 72 ++++++++++---------------------------- 1 file changed, 19 insertions(+), 53 deletions(-) diff --git a/compiler/pgates/pdriver.py b/compiler/pgates/pdriver.py index c9f45473..3a0e4e78 100644 --- a/compiler/pgates/pdriver.py +++ b/compiler/pgates/pdriver.py @@ -19,8 +19,10 @@ class pdriver(pgate.pgate): self.size_list = size_list self.fanout = fanout - if self.size_list and (self.fanout != 0 or self.neg_polarity): - debug.error("Cannot specify both size_list and neg_polarity or fanout.", -1) + if self.size_list and self.fanout != 0: + debug.error("Cannot specify both size_list and fanout.", -1) + if self.size_list and self.neg_polarity: + debug.error("Cannot specify both size_list and neg_polarity.", -1) pgate.pgate.__init__(self, name, height) debug.info(1, "Creating {}".format(self.name)) @@ -36,65 +38,29 @@ class pdriver(pgate.pgate): def compute_sizes(self): # size_list specified if self.size_list: - if not len(self.size_list) % 2: - neg_polarity = True - self.num_inv = len(self.size_list) + self.num_stages = len(self.size_list) else: - # find the number of stages - #fanout is a unit inverter fanout, not a capacitance so c_in=1 - num_stages = max(1,int(round(log(self.fanout)/log(4)))) + # Find the optimal number of stages for the given effort + self.num_stages = max(1,int(round(log(self.fanout)/log(self.stage_effort)))) - # find inv_num and compute sizes - if self.neg_polarity: - if (num_stages % 2 == 0): # if num_stages is even - self.diff_polarity(num_stages=num_stages) - else: # if num_stages is odd - self.same_polarity(num_stages=num_stages) - else: # positive polarity - if (num_stages % 2 == 0): - self.same_polarity(num_stages=num_stages) - else: - self.diff_polarity(num_stages=num_stages) + # Increase the number of stages if we need to fix polarity + if self.neg_polarity and (self.num_stages%2==0): + self.num_stages += 1 + elif not self.neg_polarity and (self.num_stages%2): + self.num_stages += 1 - - def same_polarity(self, num_stages): self.size_list = [] - self.num_inv = num_stages - # compute sizes + # compute sizes backwards from the fanout fanout_prev = self.fanout - for x in range(self.num_inv-1,-1,-1): + for x in range(self.num_stages): fanout_prev = max(round(fanout_prev/self.stage_effort),1) self.size_list.append(fanout_prev) + + # reverse the sizes to be from input to output self.size_list.reverse() - def diff_polarity(self, num_stages): - self.size_list = [] - # find which delay is smaller - if (num_stages > 1): - delay_below = ((num_stages-1)*(self.fanout**(1/num_stages-1))) + num_stages-1 - delay_above = ((num_stages+1)*(self.fanout**(1/num_stages+1))) + num_stages+1 - if (delay_above < delay_below): - # recompute stage_effort for this delay - self.num_inv = num_stages+1 - polarity_stage_effort = self.fanout**(1/self.num_inv) - else: - self.num_inv = num_stages-1 - polarity_stage_effort = self.fanout**(1/self.num_inv) - else: # num_stages is 1, can't go to 0 - self.num_inv = num_stages+1 - polarity_stage_effort = self.fanout**(1/self.num_inv) - - - fanout_prev = self.fanout - for x in range(self.num_inv-1,-1,-1): - fanout_prev = round(fanout_prev/polarity_stage_effort) - self.size_list.append(fanout_prev) - self.size_list.reverse() - def create_netlist(self): - inv_list = [] - self.add_pins() self.add_modules() self.create_insts() @@ -125,19 +91,19 @@ class pdriver(pgate.pgate): def create_insts(self): self.inv_inst_list = [] - for x in range(1,self.num_inv+1): + for x in range(1,self.num_stages+1): # Create first inverter if x == 1: zbx_int = "Zb{}_int".format(x); self.inv_inst_list.append(self.add_inst(name="buf_inv{}".format(x), mod=self.inv_list[x-1])) - if self.num_inv == 1: + if self.num_stages == 1: self.connect_inst(["A", "Z", "vdd", "gnd"]) else: self.connect_inst(["A", zbx_int, "vdd", "gnd"]) # Create last inverter - elif x == self.num_inv: + elif x == self.num_stages: zbn_int = "Zb{}_int".format(x-1); self.inv_inst_list.append(self.add_inst(name="buf_inv{}".format(x), mod=self.inv_list[x-1])) From c4438584fe2984393d39e36d62a6511b98742b7b Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Sun, 27 Jan 2019 12:59:02 -0800 Subject: [PATCH 40/44] Move jog for wl to mid-cells rather than mid-pins. --- compiler/modules/bank.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index a7e78980..ede3500f 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -1068,8 +1068,8 @@ class bank(design.design): # The mid guarantees we exit the input cell to the right. driver_wl_pos = self.wordline_driver_inst[port].get_pin("wl_{}".format(row)).rc() bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port]+"_{}".format(row)).lc() - mid1 = driver_wl_pos.scale(0.5,1)+bitcell_wl_pos.scale(0.5,0) - mid2 = driver_wl_pos.scale(0.5,0)+bitcell_wl_pos.scale(0.5,1) + mid1 = driver_wl_pos.scale(0,1) + vector(0.5*self.wordline_driver_inst[port].rx() + 0.5*self.bitcell_array_inst.lx(),0) + mid2 = mid1.scale(1,0)+bitcell_wl_pos.scale(0.5,1) self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos]) @@ -1087,8 +1087,8 @@ class bank(design.design): # The mid guarantees we exit the input cell to the right. driver_wl_pos = self.wordline_driver_inst[port].get_pin("wl_{}".format(row)).lc() bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port]+"_{}".format(row)).rc() - mid1 = driver_wl_pos.scale(0.5,1)+bitcell_wl_pos.scale(0.5,0) - mid2 = driver_wl_pos.scale(0.5,0)+bitcell_wl_pos.scale(0.5,1) + mid1 = driver_wl_pos.scale(0,1) + vector(0.5*self.wordline_driver_inst[port].lx() + 0.5*self.bitcell_array_inst.rx(),0) + mid2 = mid1.scale(1,0)+bitcell_wl_pos.scale(0.5,1) self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos]) def route_column_address_lines(self, port): From 881c449c7cd9bc6a166b0cab422cda280e3f569f Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Mon, 28 Jan 2019 07:53:36 -0800 Subject: [PATCH 41/44] Fix error in offset computation for right drivers --- compiler/modules/bank.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index ede3500f..5d4e9739 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -1088,7 +1088,7 @@ class bank(design.design): driver_wl_pos = self.wordline_driver_inst[port].get_pin("wl_{}".format(row)).lc() bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port]+"_{}".format(row)).rc() mid1 = driver_wl_pos.scale(0,1) + vector(0.5*self.wordline_driver_inst[port].lx() + 0.5*self.bitcell_array_inst.rx(),0) - mid2 = mid1.scale(1,0)+bitcell_wl_pos.scale(0.5,1) + mid2 = mid1.scale(1,0)+bitcell_wl_pos.scale(0,1) self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos]) def route_column_address_lines(self, port): From d77bba3af212138aec5497f2e81052eda670d4c1 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Mon, 28 Jan 2019 08:48:32 -0800 Subject: [PATCH 42/44] Fix clock fanout to include internal FF. Update delays in golden tests. --- compiler/modules/control_logic.py | 6 ++-- compiler/tests/21_hspice_delay_test.py | 20 ++++++------- compiler/tests/21_ngspice_delay_test.py | 40 ++++++++++++------------- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index 805cbea9..d4597cf9 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -87,11 +87,11 @@ class control_logic(design.design): height=dff_height) self.add_mod(self.and2) - # Special gates: inverters for buffering # clk_buf drives a flop for every address and control bit # plus about 5 fanouts for the control logic - clock_fanout = math.log(self.num_words,2) + math.log(self.words_per_row,2) \ - + self.num_control_signals + 5 + # each flop internally has a FO 4 approximately + clock_fanout = 4*(math.log(self.num_words,2) + math.log(self.words_per_row,2) \ + + self.num_control_signals) + 5 self.clk_buf_driver = factory.create(module_type="pdriver", fanout=clock_fanout, height=dff_height) diff --git a/compiler/tests/21_hspice_delay_test.py b/compiler/tests/21_hspice_delay_test.py index edbd6a55..7592186c 100755 --- a/compiler/tests/21_hspice_delay_test.py +++ b/compiler/tests/21_hspice_delay_test.py @@ -53,16 +53,16 @@ class timing_sram_test(openram_test): data.update(port_data[0]) if OPTS.tech_name == "freepdk45": - golden_data = {'delay_hl': [0.2011], - 'delay_lh': [0.2011], - 'leakage_power': 0.002, - 'min_period': 0.41, - 'read0_power': [0.63604], - 'read1_power': [0.6120599999999999], - 'slew_hl': [0.10853], - 'slew_lh': [0.10853], - 'write0_power': [0.51742], - 'write1_power': [0.51095]} + golden_data = {'delay_hl': [0.2152017], + 'delay_lh': [0.2152017], + 'leakage_power': 0.0022907, + 'min_period': 0.488, + 'read0_power': [0.47437749999999995], + 'read1_power': [0.45026109999999997], + 'slew_hl': [0.0846786], + 'slew_lh': [0.0846786], + 'write0_power': [0.40809259999999997], + 'write1_power': [0.4078904]} elif OPTS.tech_name == "scn4m_subm": golden_data = {'delay_hl': [1.3911], 'delay_lh': [1.3911], diff --git a/compiler/tests/21_ngspice_delay_test.py b/compiler/tests/21_ngspice_delay_test.py index 20ba14cc..aac42fa6 100755 --- a/compiler/tests/21_ngspice_delay_test.py +++ b/compiler/tests/21_ngspice_delay_test.py @@ -51,27 +51,27 @@ class timing_sram_test(openram_test): data.update(port_data[0]) if OPTS.tech_name == "freepdk45": - golden_data = {'delay_hl': [0.20443139999999999], - 'delay_lh': [0.20443139999999999], - 'leakage_power': 0.0017840640000000001, - 'min_period': 0.41, - 'read0_power': [0.6435831], - 'read1_power': [0.6233463], - 'slew_hl': [0.1138734], - 'slew_lh': [0.1138734], - 'write0_power': [0.5205761], - 'write1_power': [0.5213689]} + golden_data = {'delay_hl': [0.221699], + 'delay_lh': [0.221699], + 'leakage_power': 0.001467648, + 'min_period': 0.605, + 'read0_power': [0.3879335], + 'read1_power': [0.3662724], + 'slew_hl': [0.08562444999999999], + 'slew_lh': [0.08562444999999999], + 'write0_power': [0.3362456], + 'write1_power': [0.3372035]} elif OPTS.tech_name == "scn4m_subm": - golden_data = {'delay_hl': [1.610911], - 'delay_lh': [1.610911], - 'leakage_power': 0.0023593859999999998, - 'min_period': 3.281, - 'read0_power': [20.763569999999998], - 'read1_power': [20.32745], - 'slew_hl': [0.7986348999999999], - 'slew_lh': [0.7986348999999999], - 'write0_power': [17.58272], - 'write1_power': [18.523419999999998]} + golden_data = {'delay_hl': [1.7951730000000001], + 'delay_lh': [1.7951730000000001], + 'leakage_power': 0.001669513, + 'min_period': 3.594, + 'read0_power': [17.03022], + 'read1_power': [16.55897], + 'slew_hl': [0.7079951], + 'slew_lh': [0.7079951], + 'write0_power': [15.16726], + 'write1_power': [16.13527]} else: self.assertTrue(False) # other techs fail From f84dc3cadc2cc1158a4b458f5077a8136561c9eb Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Mon, 28 Jan 2019 10:39:09 -0800 Subject: [PATCH 43/44] Fix hspice delay golden results --- compiler/tests/21_hspice_delay_test.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/compiler/tests/21_hspice_delay_test.py b/compiler/tests/21_hspice_delay_test.py index 7592186c..d412d42f 100755 --- a/compiler/tests/21_hspice_delay_test.py +++ b/compiler/tests/21_hspice_delay_test.py @@ -64,16 +64,16 @@ class timing_sram_test(openram_test): 'write0_power': [0.40809259999999997], 'write1_power': [0.4078904]} elif OPTS.tech_name == "scn4m_subm": - golden_data = {'delay_hl': [1.3911], - 'delay_lh': [1.3911], - 'leakage_power': 0.0278488, - 'min_period': 2.812, - 'read0_power': [22.1183], - 'read1_power': [21.4388], - 'slew_hl': [0.7397553], - 'slew_lh': [0.7397553], - 'write0_power': [19.4103], - 'write1_power': [20.1167]} + golden_data = {'delay_hl': [1.4333000000000002], + 'delay_lh': [1.4333000000000002], + 'leakage_power': 0.0271847, + 'min_period': 2.891, + 'read0_power': [15.714200000000002], + 'read1_power': [14.9848], + 'slew_hl': [0.6819276999999999], + 'slew_lh': [0.6819276999999999], + 'write0_power': [13.9658], + 'write1_power': [14.8422]} else: self.assertTrue(False) # other techs fail # Check if no too many or too few results From 1bdf4dbe4f404eab7449491ab074018a96c51e24 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Mon, 28 Jan 2019 17:07:38 -0800 Subject: [PATCH 44/44] Re-enable abort on supply error. --- compiler/verify/calibre.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/verify/calibre.py b/compiler/verify/calibre.py index 4eb05448..a1bbbc3e 100644 --- a/compiler/verify/calibre.py +++ b/compiler/verify/calibre.py @@ -182,10 +182,7 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False): # FIXME: Remove when vdd/gnd connected #'lvsAbortOnSupplyError' : 0 - # This should be removed for final verification - # FIXMEFIXMEFIXME - # MRG: Just doing this to merge pdriver - if True or not final_verification: + if not final_verification: lvs_runset['cmnVConnectReport']=1 lvs_runset['cmnVConnectNamesState']='SOME' lvs_runset['cmnVConnectNames']='vdd gnd'