diff --git a/.gitignore b/.gitignore index bf2aa7b7..c1ae7065 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,7 @@ *~ *.pyc *.log +*.aux +*.out +*.toc +*.synctex.gz diff --git a/README.md b/README.md index f96923cf..58c8e505 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,14 @@ https://github.com/mguthaus/OpenRAM/blob/master/OpenRAM_ICCAD_2016_presentation. The OpenRAM compiler has very few dependencies: * ngspice-26 (or later) or HSpice I-2013.12-1 (or later) or CustomSim 2017 (or later) * Python 2.7 and higher (currently excludes Python 3 and up) +* Python numpy * a setup script for each technology * a technology directory for each technology with the base cells +If you want to perform DRC and LVS, you will need either: +* Calibre (for FreePDK45 or SCMOS) +* Magic + Netgen (for SCMOS only) + You must set two environment variables: OPENRAM_HOME should point to the compiler source directory. OPENERAM_TECH should point to a root technology directory that contains subdirs of all other technologies. @@ -36,6 +41,12 @@ For example, in csh/tcsh, add to your .tcshrc: We do not distribute the PDK, but you may get it from: https://www.eda.ncsu.edu/wiki/FreePDK45:Contents +If you are using SCMOS, you should install Magic and netgen from: + http://opencircuitdesign.com/magic/ + http://opencircuitdesign.com/netgen/ +In addition, you will need to install the MOSIS SCMOS rules for scn3me_subm +that are part of QFlow: + http://opencircuitdesign.com/qflow/ # DIRECTORY STRUCTURE @@ -120,27 +131,34 @@ This is where simulations and DRC/LVS get run so there is no network traffic. The directory name is unique for each person and run of OpenRAM to not clobber any files and allow simultaneous runs. If it passes, the files are deleted. If it fails, you will see these files: -* _calibreDRC.rul_ is the DRC rule file. -* dc_runset is the command file for caliber. * temp.gds is the layout -* test1.drc.err is the std err output of the command -* test1.drc.out is the standard output of the command -* test1.drc.db is the DRC results file +* (.mag files if using SCMOS) +* temp.sp is the netlist +* test1.drc.err is the std err output of the DRC command +* test1.drc.out is the standard output of the DRC command +* test1.drc.results is the DRC results file +* test1.lvs.err is the std err output of the LVS command +* test1.lvs.out is the standard output of the LVS command +* test1.lvs.results is the DRC results file + +Depending on your DRC/LVS tools, there will also be: +* _calibreDRC.rul_ is the DRC rule file (Calibre) +* dc_runset is the command file (Calibre) +* extracted.sp (Calibre) +* run_lvs.sh is a Netgen script for LVS (Netgen) +* run_drc.sh is a Magic script for DRC (Magic) +* .spice (Magic) If DRC/LVS fails, the first thing is to check if it ran in the .out and .err file. This shows the standard output and error output from running DRC/LVS. If there is a setup problem it will be shown here. -If DRC/LVS runs, but doesn't pass, you then should look at the .db +If DRC/LVS runs, but doesn't pass, you then should look at the .results file. If the DRC fails, it will typically show you the command that was used -to run caliber. It is something like this: -``` - calibre -gui -drc /tmp/openram_mrg_28781_temp/drc_runset -batch 2> - /tmp/openram_mrg_28781_temp/test1.drc.err 1> - /tmp/openram_mrg_28781_temp/test1.drc.out -``` -To debug, you will need a layout viewer. I prefer to use glade on my -Mac, but you can also use Calibre, Magic, etc. +to run Calibre or Magic+Netgen. + +To debug, you will need a layout viewer. I prefer to use Glade +on my Mac, but you can also use Calibre, Magic, etc. 1. Calibre @@ -184,12 +202,19 @@ ui().importCds("default", between processes, you have to change the importCds command (or you can manually run the command each time you start glade). - To load the errors, you simply do Verify->Import Caliber Errors select - the .db file from calibre. + To load the errors, you simply do Verify->Import Calibre Errors select + the .results file from Calibre. -3. It is possible to use other viewers as well, such as: +3. Magic + + Magic is only supported in SCMOS. You will need to install the MOSIS SCMOS rules + and Magic from: http://opencircuitdesign.com/ + + When running DRC or extraction, OpenRAM will load the GDS file, save + the .ext/.mag files, and export an extracted netlist (.spice). + +4. It is possible to use other viewers as well, such as: * LayoutEditor http://www.layouteditor.net/ - * Magic http://opencircuitdesign.com/magic/ # Example to output/input .gds layout files from/to Cadence diff --git a/compiler/contact.py b/compiler/base/contact.py similarity index 100% rename from compiler/contact.py rename to compiler/base/contact.py diff --git a/compiler/design.py b/compiler/base/design.py similarity index 95% rename from compiler/design.py rename to compiler/base/design.py index f32807d2..39ad1792 100644 --- a/compiler/design.py +++ b/compiler/base/design.py @@ -77,7 +77,7 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout): return inst_map - def DRC_LVS(self): + def DRC_LVS(self, final_verification=False): """Checks both DRC and LVS for a module""" if OPTS.check_lvsdrc: tempspice = OPTS.openram_temp + "/temp.sp" @@ -85,7 +85,7 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout): self.sp_write(tempspice) self.gds_write(tempgds) debug.check(verify.run_drc(self.name, tempgds) == 0,"DRC failed for {0}".format(self.name)) - debug.check(verify.run_lvs(self.name, tempgds, tempspice) == 0,"LVS failed for {0}".format(self.name)) + debug.check(verify.run_lvs(self.name, tempgds, tempspice, final_verification) == 0,"LVS failed for {0}".format(self.name)) os.remove(tempspice) os.remove(tempgds) @@ -97,14 +97,14 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout): debug.check(verify.run_drc(self.name, tempgds) == 0,"DRC failed for {0}".format(self.name)) os.remove(tempgds) - def LVS(self): + def LVS(self, final_verification=False): """Checks LVS for a module""" if OPTS.check_lvsdrc: tempspice = OPTS.openram_temp + "/temp.sp" tempgds = OPTS.openram_temp + "/temp.gds" self.sp_write(tempspice) self.gds_write(tempgds) - debug.check(verify.run_lvs(self.name, tempgds, tempspice) == 0,"LVS failed for {0}".format(self.name)) + debug.check(verify.run_lvs(self.name, tempgds, tempspice, final_verification) == 0,"LVS failed for {0}".format(self.name)) os.remove(tempspice) os.remove(tempgds) diff --git a/compiler/geometry.py b/compiler/base/geometry.py similarity index 100% rename from compiler/geometry.py rename to compiler/base/geometry.py diff --git a/compiler/hierarchy_layout.py b/compiler/base/hierarchy_layout.py similarity index 93% rename from compiler/hierarchy_layout.py rename to compiler/base/hierarchy_layout.py index dc923d44..81ca717d 100644 --- a/compiler/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -60,21 +60,44 @@ class layout(lef.lef): def find_lowest_coords(self): """Finds the lowest set of 2d cartesian coordinates within this layout""" - - lowestx1 = min(obj.lx() for obj in self.objs if obj.name!="label") - lowesty1 = min(obj.by() for obj in self.objs if obj.name!="label") - lowestx2 = min(inst.lx() for inst in self.insts) - lowesty2 = min(inst.by() for inst in self.insts) - return vector(min(lowestx1, lowestx2), min(lowesty1, lowesty2)) + + if len(self.objs)>0: + lowestx1 = min(obj.lx() for obj in self.objs if obj.name!="label") + lowesty1 = min(obj.by() for obj in self.objs if obj.name!="label") + else: + lowestx1=lowesty1=None + if len(self.insts)>0: + lowestx2 = min(inst.lx() for inst in self.insts) + lowesty2 = min(inst.by() for inst in self.insts) + else: + lowestx2=lowesty2=None + if lowestx1==None: + return vector(lowestx2,lowesty2) + elif lowestx2==None: + return vector(lowestx1,lowesty1) + else: + return vector(min(lowestx1, lowestx2), min(lowesty1, lowesty2)) def find_highest_coords(self): """Finds the highest set of 2d cartesian coordinates within this layout""" - highestx1 = min(obj.rx() for obj in self.objs if obj.name!="label") - highesty1 = min(obj.uy() for obj in self.objs if obj.name!="label") - highestx2 = min(inst.rx() for inst in self.insts) - highesty2 = min(inst.uy() for inst in self.insts) - return vector(min(highestx1, highestx2), min(highesty1, highesty2)) + + if len(self.objs)>0: + highestx1 = max(obj.rx() for obj in self.objs if obj.name!="label") + highesty1 = max(obj.uy() for obj in self.objs if obj.name!="label") + else: + highestx1=highesty1=None + if len(self.insts)>0: + highestx2 = max(inst.rx() for inst in self.insts) + highesty2 = max(inst.uy() for inst in self.insts) + else: + highestx2=highesty2=None + if highestx1==None: + return vector(highestx2,highesty2) + elif highestx2==None: + return vector(highestx1,highesty1) + else: + return vector(max(highestx1, highestx2), max(highesty1, highesty2)) def translate_all(self, offset): @@ -143,9 +166,11 @@ class layout(lef.lef): debug.error("Nonrectilinear center rect!",-1) elif start.x!=end.x: offset = vector(0,0.5*minwidth_layer) + return self.add_rect(layer,start-offset,end.x-start.x,minwidth_layer) else: offset = vector(0.5*minwidth_layer,0) - return self.add_rect(layer,start-offset,end.x-start.x,minwidth_layer) + return self.add_rect(layer,start-offset,minwidth_layer,end.y-start.y) + def get_pin(self, text): @@ -283,7 +308,7 @@ class layout(lef.lef): path.path(obj=self, layer=layer, position_list=coordinates, - width=drc["minwidth_{}".format(layer)]) + width=width) def add_route(self, design, layers, coordinates): """Connects a routing path on given layer,coordinates,width. The diff --git a/compiler/hierarchy_spice.py b/compiler/base/hierarchy_spice.py similarity index 100% rename from compiler/hierarchy_spice.py rename to compiler/base/hierarchy_spice.py diff --git a/compiler/lef.py b/compiler/base/lef.py similarity index 100% rename from compiler/lef.py rename to compiler/base/lef.py diff --git a/compiler/path.py b/compiler/base/path.py similarity index 93% rename from compiler/path.py rename to compiler/base/path.py index 2ce313fb..ed058fef 100644 --- a/compiler/path.py +++ b/compiler/base/path.py @@ -92,7 +92,8 @@ class path(): self.add_line(layer_name=self.layer_name, length=abs(line_length), offset=offset, - orientation="horizontal") + orientation="horizontal", + layer_width=self.layer_width) # if we have y motion elif pl[index][1] != pl[index + 1][1]: line_length = pl[index + 1][1] - pl[index][1] @@ -104,15 +105,15 @@ class path(): self.add_line(layer_name=self.layer_name, length=abs(line_length), offset=offset, - orientation="vertical") + orientation="vertical", + layer_width=self.layer_width) - def add_line(self, layer_name, length, offset, orientation): + def add_line(self, layer_name, length, offset, orientation, layer_width): """ straight line object with layer_minwidth (orientation: "vertical" or "horizontal") default is vertical """ - layer_width = drc["minwidth_{0}".format(layer_name)] width = layer_width height = length diff --git a/compiler/pin_layout.py b/compiler/base/pin_layout.py similarity index 100% rename from compiler/pin_layout.py rename to compiler/base/pin_layout.py diff --git a/compiler/route.py b/compiler/base/route.py similarity index 98% rename from compiler/route.py rename to compiler/base/route.py index 9e643bc7..03b62cff 100644 --- a/compiler/route.py +++ b/compiler/base/route.py @@ -7,7 +7,7 @@ from vector3d import vector3d class route(): """ - Object route + Object route (used by the router module) Add a route of minimium metal width between a set of points. The wire must be completely rectilinear and the z-dimension of the points refers to the layers (plus via) diff --git a/compiler/utils.py b/compiler/base/utils.py similarity index 100% rename from compiler/utils.py rename to compiler/base/utils.py diff --git a/compiler/vector.py b/compiler/base/vector.py similarity index 100% rename from compiler/vector.py rename to compiler/base/vector.py diff --git a/compiler/verilog.py b/compiler/base/verilog.py similarity index 100% rename from compiler/verilog.py rename to compiler/base/verilog.py diff --git a/compiler/wire.py b/compiler/base/wire.py similarity index 95% rename from compiler/wire.py rename to compiler/base/wire.py index 879baf9b..9220c77a 100644 --- a/compiler/wire.py +++ b/compiler/base/wire.py @@ -12,8 +12,6 @@ class wire(path): The points are the center of the wire. The layer stack is the vertical, contact/via, and horizontal layers, respectively. """ - unique_id = 1 - def __init__(self, obj, layer_stack, position_list): self.obj = obj self.layer_stack = layer_stack @@ -85,7 +83,8 @@ class wire(path): self.add_line(layer_name=self.horiz_layer_name, length=abs(line_length), offset=temp_offset, - orientation="horizontal") + orientation="horizontal", + layer_width=self.horiz_layer_width) elif pl[index][1] != pl[index + 1][1]: line_length = pl[index + 1][1] - pl[index][1] temp_offset = [pl[index][0] - 0.5 * self.vert_layer_width, @@ -96,7 +95,8 @@ class wire(path): self.add_line(layer_name=self.vert_layer_name, length=abs(line_length), offset=temp_offset, - orientation="vertical") + orientation="vertical", + layer_width=self.vert_layer_width) def assert_node(self, A, B): """ Check if the node movements are not big enough for the diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index f303374c..82515933 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -10,20 +10,25 @@ from globals import OPTS class delay(): """ - Functions to measure the delay of the SRAM at a given address and + Functions to measure the delay of an SRAM at a given address and data bit. """ - def __init__(self,sram,spfile): + def __init__(self,sram,spfile, corner): self.name = sram.name self.num_words = sram.num_words self.word_size = sram.word_size self.addr_size = sram.addr_size self.sram_sp_file = spfile - self.vdd = tech.spice["supply_voltage"] - self.gnd = tech.spice["gnd_voltage"] - + self.set_corner(corner) + + def set_corner(self,corner): + """ Set the corner values """ + self.corner = corner + (self.process, self.vdd_voltage, self.temperature) = corner + self.gnd_voltage = 0 + def check_arguments(self): """Checks if arguments given for write_stimulus() meets requirements""" @@ -40,9 +45,9 @@ class delay(): def write_stimulus(self, period, load, slew): - """Creates a stimulus file for simulations to probe a certain bitcell, given an address and data-position of the data-word - (probe-address form: '111010000' LSB=0, MSB=1) - (probe_data form: number corresponding to the bit position of data-bus, begins with position 0) + """ Creates a stimulus file for simulations to probe a bitcell at a given clock period. + Address and bit were previously set with set_probe(). + Input slew (in ns) and output capacitive load (in fF) are required for charaterization. """ self.check_arguments() @@ -52,159 +57,160 @@ class delay(): # creates and opens stimulus file for writing temp_stim = "{0}/stim.sp".format(OPTS.openram_temp) self.sf = open(temp_stim, "w") - self.sf.write("* Stimulus for period of {0}n load={1} slew={2}\n\n".format(period,load,slew)) - + self.sf.write("* Stimulus for period of {0}n load={1}fF slew={2}ns\n\n".format(period,load,slew)) + self.stim = stimuli.stimuli(self.sf, self.corner) # include files in stimulus file - model_list = tech.spice["fet_models"] + [self.sram_sp_file] - stimuli.write_include(stim_file=self.sf, models=model_list) + self.stim.write_include(self.sram_sp_file) # add vdd/gnd statements - self.sf.write("* Global Power Supplies\n") - stimuli.write_supply(self.sf) + self.sf.write("\n* Global Power Supplies\n") + self.stim.write_supply() # instantiate the sram - self.sf.write("* Instantiation of the SRAM\n") - stimuli.inst_sram(stim_file=self.sf, - abits=self.addr_size, - dbits=self.word_size, - sram_name=self.name) + self.sf.write("\n* Instantiation of the SRAM\n") + self.stim.inst_sram(abits=self.addr_size, + dbits=self.word_size, + sram_name=self.name) - self.sf.write("* SRAM output loads\n") + self.sf.write("\n* SRAM output loads\n") for i in range(self.word_size): self.sf.write("CD{0} d[{0}] 0 {1}f\n".format(i,load)) # add access transistors for data-bus - self.sf.write("* Transmission Gates for data-bus and control signals\n") - stimuli.inst_accesstx(stim_file=self.sf, dbits=self.word_size) + self.sf.write("\n* Transmission Gates for data-bus and control signals\n") + self.stim.inst_accesstx(dbits=self.word_size) # generate data and addr signals - self.sf.write("* Generation of data and address signals\n") + self.sf.write("\n* Generation of data and address signals\n") for i in range(self.word_size): if i == self.probe_data: - stimuli.gen_data(stim_file=self.sf, - clk_times=self.cycle_times, - sig_name="data[{0}]".format(i), - period=period, - slew=slew) + self.gen_data(clk_times=self.cycle_times, + sig_name="data[{0}]".format(i), + period=period, + slew=slew) else: - stimuli.gen_constant(stim_file=self.sf, - sig_name="d[{0}]".format(i), - v_val=self.gnd) + self.stim.gen_constant(sig_name="d[{0}]".format(i), + v_val=self.gnd_voltage) - stimuli.gen_addr(self.sf, - clk_times=self.cycle_times, - addr=self.probe_address, - period=period, - slew=slew) + self.gen_addr(clk_times=self.cycle_times, + addr=self.probe_address, + period=period, + slew=slew) # generate control signals - self.sf.write("* Generation of control signals\n") - stimuli.gen_csb(self.sf, self.cycle_times, period, slew) - stimuli.gen_web(self.sf, self.cycle_times, period, slew) - stimuli.gen_oeb(self.sf, self.cycle_times, period, slew) + self.sf.write("\n* Generation of control signals\n") + self.gen_csb(self.cycle_times, period, slew) + self.gen_web(self.cycle_times, period, slew) + self.gen_oeb(self.cycle_times, period, slew) - self.sf.write("* Generation of global clock signal\n") - stimuli.gen_pulse(stim_file=self.sf, - sig_name="CLK", - v1=self.gnd, - v2=self.vdd, - offset=period, - period=period, - t_rise = slew, - t_fall = slew) + self.sf.write("\n* Generation of global clock signal\n") + self.stim.gen_pulse(sig_name="CLK", + v1=self.gnd_voltage, + v2=self.vdd_voltage, + offset=period, + period=period, + t_rise=slew, + t_fall=slew) self.write_measures(period) - # run until the last cycle time - stimuli.write_control(self.sf,self.cycle_times[-1]) + # run until the end of the cycle time + self.stim.write_control(self.cycle_times[-1] + period) self.sf.close() def write_measures(self,period): - # meas statement for delay and power measurements - self.sf.write("* Measure statements for delay and power\n") + """ + Write the measure statements to quantify the delay and power results. + """ + self.sf.write("\n* Measure statements for delay and power\n") + + # Output some comments to aid where cycles start and + # what is happening + for comment in self.cycle_comments: + self.sf.write("* {}\n".format(comment)) + + # Trigger on the clk of the appropriate cycle trig_name = "clk" targ_name = "{0}".format("d[{0}]".format(self.probe_data)) - trig_val = targ_val = 0.5 * self.vdd - # add measure statments for delay0 - # delay the target to measure after the negetive edge - stimuli.gen_meas_delay(stim_file=self.sf, - meas_name="DELAY0", - trig_name=trig_name, - targ_name=targ_name, - trig_val=trig_val, - targ_val=targ_val, - trig_dir="FALL", - targ_dir="FALL", - td=self.cycle_times[self.read0_cycle]+0.5*period) + trig_val = targ_val = 0.5 * self.vdd_voltage - stimuli.gen_meas_delay(stim_file=self.sf, - meas_name="DELAY1", - trig_name=trig_name, - targ_name=targ_name, - trig_val=trig_val, - targ_val=targ_val, - trig_dir="FALL", - targ_dir="RISE", - td=self.cycle_times[self.read1_cycle]+0.5*period) + # Delay the target to measure after the negative edge + self.stim.gen_meas_delay(meas_name="DELAY0", + trig_name=trig_name, + targ_name=targ_name, + trig_val=trig_val, + targ_val=targ_val, + trig_dir="FALL", + targ_dir="FALL", + trig_td=self.cycle_times[self.read0_cycle], + targ_td=self.cycle_times[self.read0_cycle]+0.5*period) - stimuli.gen_meas_delay(stim_file=self.sf, - meas_name="SLEW0", - trig_name=targ_name, - targ_name=targ_name, - trig_val=0.9*self.vdd, - targ_val=0.1*self.vdd, - trig_dir="FALL", - targ_dir="FALL", - td=self.cycle_times[self.read0_cycle]+0.5*period) + self.stim.gen_meas_delay(meas_name="DELAY1", + trig_name=trig_name, + targ_name=targ_name, + trig_val=trig_val, + targ_val=targ_val, + trig_dir="FALL", + targ_dir="RISE", + trig_td=self.cycle_times[self.read1_cycle], + targ_td=self.cycle_times[self.read1_cycle]+0.5*period) - stimuli.gen_meas_delay(stim_file=self.sf, - meas_name="SLEW1", - trig_name=targ_name, - targ_name=targ_name, - trig_val=0.1*self.vdd, - targ_val=0.9*self.vdd, - trig_dir="RISE", - targ_dir="RISE", - td=self.cycle_times[self.read1_cycle]+0.5*period) + self.stim.gen_meas_delay(meas_name="SLEW0", + trig_name=targ_name, + targ_name=targ_name, + trig_val=0.9*self.vdd_voltage, + targ_val=0.1*self.vdd_voltage, + trig_dir="FALL", + targ_dir="FALL", + trig_td=self.cycle_times[self.read0_cycle], + targ_td=self.cycle_times[self.read0_cycle]+0.5*period) + + self.stim.gen_meas_delay(meas_name="SLEW1", + trig_name=targ_name, + targ_name=targ_name, + trig_val=0.1*self.vdd_voltage, + targ_val=0.9*self.vdd_voltage, + trig_dir="RISE", + targ_dir="RISE", + trig_td=self.cycle_times[self.read1_cycle], + targ_td=self.cycle_times[self.read1_cycle]+0.5*period) # add measure statements for power t_initial = self.cycle_times[self.write0_cycle] t_final = self.cycle_times[self.write0_cycle+1] - stimuli.gen_meas_power(stim_file=self.sf, - meas_name="WRITE0_POWER", - t_initial=t_initial, - t_final=t_final) + self.stim.gen_meas_power(meas_name="WRITE0_POWER", + t_initial=t_initial, + t_final=t_final) t_initial = self.cycle_times[self.write1_cycle] t_final = self.cycle_times[self.write1_cycle+1] - stimuli.gen_meas_power(stim_file=self.sf, - meas_name="WRITE1_POWER", - t_initial=t_initial, - t_final=t_final) + self.stim.gen_meas_power(meas_name="WRITE1_POWER", + t_initial=t_initial, + t_final=t_final) t_initial = self.cycle_times[self.read0_cycle] t_final = self.cycle_times[self.read0_cycle+1] - stimuli.gen_meas_power(stim_file=self.sf, - meas_name="READ0_POWER", - t_initial=t_initial, - t_final=t_final) + self.stim.gen_meas_power(meas_name="READ0_POWER", + t_initial=t_initial, + t_final=t_final) t_initial = self.cycle_times[self.read1_cycle] t_final = self.cycle_times[self.read1_cycle+1] - stimuli.gen_meas_power(stim_file=self.sf, - meas_name="READ1_POWER", - t_initial=t_initial, - t_final=t_final) + self.stim.gen_meas_power(meas_name="READ1_POWER", + t_initial=t_initial, + t_final=t_final) def find_feasible_period(self, load, slew): - """Uses an initial period and finds a feasible period before we + """ + Uses an initial period and finds a feasible period before we run the binary search algorithm to find min period. We check if the given clock period is valid and if it's not, we continue to double the period until we find a valid period to use as a - starting point. """ + starting point. + """ feasible_period = tech.spice["feasible_period"] time_out = 8 @@ -220,17 +226,23 @@ class delay(): feasible_period = 2 * feasible_period continue - debug.info(1, "Found feasible_period: {0}ns feasible_delay1/0 {1}ns/{2}ns slew {3}ns/{4}ns".format(feasible_period,feasible_delay1,feasible_delay0,feasible_slew1,feasible_slew0)) + debug.info(1, "Found feasible_period: {0}ns feasible_delay1/0 {1}ns/{2}ns slew {3}ns/{4}ns".format(feasible_period, + feasible_delay1, + feasible_delay0, + feasible_slew1, + feasible_slew0)) return (feasible_period, feasible_delay1, feasible_delay0) def run_simulation(self, period, load, slew): - """ This tries to simulate a period and checks if the result - works. If so, it returns True and the delays and slews.""" + """ + This tries to simulate a period and checks if the result + works. If so, it returns True and the delays and slews. + """ # Checking from not data_value to data_value self.write_stimulus(period, load, slew) - stimuli.run_sim() + self.stim.run_sim() delay0 = ch.convert_to_float(ch.parse_output("timing", "delay0")) delay1 = ch.convert_to_float(ch.parse_output("timing", "delay1")) slew0 = ch.convert_to_float(ch.parse_output("timing", "slew0")) @@ -238,15 +250,37 @@ class delay(): # if it failed or the read was longer than a period if type(delay0)!=float or type(delay1)!=float or type(slew1)!=float or type(slew0)!=float: + debug.info(2,"Failed simulation: period {0} load {1} slew {2}, delay0={3}n delay1={4}ns slew0={5}n slew1={6}n".format(period, + load, + slew, + delay0, + delay1, + slew0, + slew1)) return (False,0,0,0,0) + # Scale delays to ns (they previously could have not been floats) delay0 *= 1e9 delay1 *= 1e9 slew0 *= 1e9 slew1 *= 1e9 if delay0>period or delay1>period or slew0>period or slew1>period: + debug.info(2,"UNsuccessful simulation: period {0} load {1} slew {2}, delay0={3}n delay1={4}ns slew0={5}n slew1={6}n".format(period, + load, + slew, + delay0, + delay1, + slew0, + slew1)) return (False,0,0,0,0) else: - debug.info(2,"Successful simulation: period {0} load {1} slew {2}, delay0={3}n delay1={4}ns slew0={5}n slew1={6}n".format(period,load,slew,delay0,delay1,slew0,slew1)) + debug.info(2,"Successful simulation: period {0} load {1} slew {2}, delay0={3}n delay1={4}ns slew0={5}n slew1={6}n".format(period, + load, + slew, + delay0, + delay1, + slew0, + slew1)) + # For debug, you sometimes want to inspect each simulation. #key=raw_input("press return to continue") # The delay is from the negative edge for our SRAM @@ -255,8 +289,10 @@ class delay(): def find_min_period(self,feasible_period, load, slew, feasible_delay1, feasible_delay0): - """Searches for the smallest period with output delays being within 5% of - long period. """ + """ + Searches for the smallest period with output delays being within 5% of + long period. + """ previous_period = ub_period = feasible_period lb_period = 0.0 @@ -284,26 +320,36 @@ class delay(): def try_period(self, period, load, slew, feasible_delay1, feasible_delay0): - """ This tries to simulate a period and checks if the result - works. If it does and the delay is within 5% still, it returns True.""" + """ + This tries to simulate a period and checks if the result + works. If it does and the delay is within 5% still, it returns True. + """ # Checking from not data_value to data_value self.write_stimulus(period,load,slew) - stimuli.run_sim() + self.stim.run_sim() delay0 = ch.convert_to_float(ch.parse_output("timing", "delay0")) delay1 = ch.convert_to_float(ch.parse_output("timing", "delay1")) slew0 = ch.convert_to_float(ch.parse_output("timing", "slew0")) slew1 = ch.convert_to_float(ch.parse_output("timing", "slew1")) # if it failed or the read was longer than a period if type(delay0)!=float or type(delay1)!=float or type(slew1)!=float or type(slew0)!=float: - debug.info(2,"Invalid measures: Period {0}, delay0={1}ns, delay1={2}ns slew0={3}ns slew1={4}ns".format(period, delay0, delay1, slew0, slew1)) + debug.info(2,"Invalid measures: Period {0}, delay0={1}ns, delay1={2}ns slew0={3}ns slew1={4}ns".format(period, + delay0, + delay1, + slew0, + slew1)) return False delay0 *= 1e9 delay1 *= 1e9 slew0 *= 1e9 slew1 *= 1e9 if delay0>period or delay1>period or slew0>period or slew1>period: - debug.info(2,"Too long delay/slew: Period {0}, delay0={1}ns, delay1={2}ns slew0={3}ns slew1={4}ns".format(period, delay0, delay1, slew0, slew1)) + debug.info(2,"Too long delay/slew: Period {0}, delay0={1}ns, delay1={2}ns slew0={3}ns slew1={4}ns".format(period, + delay0, + delay1, + slew0, + slew1)) return False else: if not ch.relative_compare(delay1,feasible_delay1,error_tolerance=0.05): @@ -316,7 +362,11 @@ class delay(): #key=raw_input("press return to continue") - debug.info(2,"Successful period {0}, delay0={1}ns, delay1={2}ns slew0={3}ns slew1={4}ns".format(period, delay0, delay1, slew0, slew1)) + debug.info(2,"Successful period {0}, delay0={1}ns, delay1={2}ns slew0={3}ns slew1={4}ns".format(period, + delay0, + delay1, + slew0, + slew1)) return True def set_probe(self,probe_address, probe_data): @@ -394,47 +444,96 @@ class delay(): of the cycles to do a timing evaluation. The last time is the end of the simulation and does not need a rising edge.""" - # idle cycle, no operation - t_current = period + self.cycle_comments = [] self.cycle_times = [] - - # cycle0: W data 1 address 1111 to initialize cell to a value + t_current = 0 + + # idle cycle, no operation + msg = "Idle cycle (no clock)" + self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(0, + t_current, + msg)) self.cycle_times.append(t_current) t_current += period - # cycle1: W data 0 address 1111 (to ensure a write of value works) + # One period + msg = "W data 1 address 11..11 to initialize cell" self.cycle_times.append(t_current) - self.write0_cycle=1 + self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(len(self.cycle_times)-1, + t_current, + msg)) + t_current += period + + # One period + msg = "W data 0 address 11..11 (to ensure a write of value works)" + self.cycle_times.append(t_current) + self.write0_cycle=len(self.cycle_times)-1 + self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(len(self.cycle_times)-1, + t_current, + msg)) t_current += period - # cycle2: W data 1 address 0000 (to clear the data bus cap) + # One period + msg = "W data 1 address 00..00 (to clear bus caps)" + self.cycle_times.append(t_current) + self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(len(self.cycle_times)-1, + t_current, + msg)) + t_current += period + + # One period + msg = "R data 0 address 11..11 to check W0 worked" + self.cycle_times.append(t_current) + self.read0_cycle=len(self.cycle_times)-1 + self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(len(self.cycle_times)-1, + t_current, + msg)) + t_current += period + + # One period + msg = "Idle cycle" + self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(len(self.cycle_times)-1, + t_current, + msg)) self.cycle_times.append(t_current) t_current += period - # cycle3: R data 0 address 1111 to check W0 works + # One period + msg = "W data 1 address 11..11 (to ensure a write of value worked)" self.cycle_times.append(t_current) - self.read0_cycle=3 + self.write1_cycle=len(self.cycle_times)-1 + self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(len(self.cycle_times)-1, + t_current, + msg)) t_current += period - # cycle4: W data 1 address 1111 (to ensure a write of value works) - self.cycle_times.append(t_current) - self.write1_cycle=4 - t_current += period - - # cycle5: W data 0 address 0000 (to clear the data bus cap) + # One period + msg = "W data 0 address 00..00 (to clear bus caps)" self.cycle_times.append(t_current) + self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(len(self.cycle_times)-1, + t_current, + msg)) t_current += period - # cycle6: R data 1 address 1111 to check W1 works + # One period + msg = "R data 1 address 11..11 to check W1 worked" self.cycle_times.append(t_current) - self.read1_cycle=6 + self.read1_cycle=len(self.cycle_times)-1 + self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(len(self.cycle_times)-1, + t_current, + msg)) t_current += period - # cycle7: wait a clock period to end the simulation + # One period + msg = "Idle cycle" + self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(len(self.cycle_times)-1, + t_current, + msg)) self.cycle_times.append(t_current) t_current += period + def analytical_model(self,sram, slews, loads): """ Just return the analytical model results for the SRAM. """ @@ -465,3 +564,54 @@ class delay(): } return data + def gen_data(self, clk_times, sig_name, period, slew): + """ Generates the PWL data inputs for a simulation timing test. """ + # values for NOP, W1, W0, W1, R0, NOP, W1, W0, R1, NOP + # we are asserting the opposite value on the other side of the tx gate during + # the read to be "worst case". Otherwise, it can actually assist the read. + values = [0, 1, 0, 1, 1, 1, 1, 0, 0, 0 ] + self.stim.gen_pwl(sig_name, clk_times, values, period, slew, 0.05) + + def gen_addr(self, clk_times, addr, period, slew): + """ + Generates the address inputs for a simulation timing test. + This alternates between all 1's and all 0's for the address. + """ + + zero_values = [0, 0, 0, 1, 0, 0, 0, 1, 0, 0 ] + ones_values = [1, 1, 1, 0, 1, 0, 1, 0, 1, 1 ] + + for i in range(len(addr)): + sig_name = "A[{0}]".format(i) + if addr[i]=="1": + self.stim.gen_pwl(sig_name, clk_times, ones_values, period, slew, 0.05) + else: + self.stim.gen_pwl(sig_name, clk_times, zero_values, period, slew, 0.05) + + + def gen_csb(self, clk_times, period, slew): + """ Generates the PWL CSb signal """ + # values for NOP, W1, W0, W1, R0, NOP, W1, W0, R1, NOP + # Keep CSb asserted in NOP for measuring >1 period + values = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0] + self.stim.gen_pwl("csb", clk_times, values, period, slew, 0.05) + + def gen_web(self, clk_times, period, slew): + """ Generates the PWL WEb signal """ + # values for NOP, W1, W0, W1, R0, NOP, W1, W0, R1, NOP + # Keep WEb deasserted in NOP for measuring >1 period + values = [1, 0, 0, 0, 1, 1, 0, 0, 1, 1] + self.stim.gen_pwl("web", clk_times, values, period, slew, 0.05) + + # Keep acc_en deasserted in NOP for measuring >1 period + values = [1, 0, 0, 0, 1, 1, 0, 0, 1, 1] + self.stim.gen_pwl("acc_en", clk_times, values, period, slew, 0) + values = [0, 1, 1, 1, 0, 0, 1, 1, 0, 0] + self.stim.gen_pwl("acc_en_inv", clk_times, values, period, slew, 0) + + def gen_oeb(self, clk_times, period, slew): + """ Generates the PWL WEb signal """ + # values for NOP, W1, W0, W1, R0, W1, W0, R1, NOP + # Keep OEb asserted in NOP for measuring >1 period + values = [1, 1, 1, 1, 0, 0, 1, 1, 0, 0] + self.stim.gen_pwl("oeb", clk_times, values, period, slew, 0.05) diff --git a/compiler/characterizer/lib.py b/compiler/characterizer/lib.py index b2a87479..c43f2975 100644 --- a/compiler/characterizer/lib.py +++ b/compiler/characterizer/lib.py @@ -1,8 +1,5 @@ -import os -import sys -import re +import os,sys,re,shutil import debug -import tech import math import setup_hold import delay @@ -15,15 +12,23 @@ from globals import OPTS class lib: """ lib file generation.""" - def __init__(self, libname, sram, spfile, use_model=OPTS.analytical_delay): + def __init__(self, out_dir, sram, sp_file, use_model=OPTS.analytical_delay): + self.out_dir = out_dir self.sram = sram - self.sp_file = spfile + self.sp_file = sp_file self.use_model = use_model - self.name = sram.name - self.num_words = sram.num_words - self.word_size = sram.word_size - self.addr_size = sram.addr_size + self.prepare_netlist() + + self.prepare_tables() + + self.create_corners() + + self.characterize_corners() + + def prepare_netlist(self): + """ Determine whether to use regular or trimmed netlist. """ + # Set up to trim the netlist here if that is enabled if OPTS.trim_netlist: self.sim_sp_file = "{}reduced.sp".format(OPTS.openram_temp) @@ -34,13 +39,17 @@ class lib: self.sram.word_size) else: # Else, use the non-reduced netlist file for simulation - self.sim_sp_file = self.sp_file - + self.sim_sp_file = "{}sram.sp".format(OPTS.openram_temp) + # Make a copy in temp for debugging + shutil.copy(self.sp_file, self.sim_sp_file) + + def prepare_tables(self): + """ Determine the load/slews if they aren't specified in the config file. """ # These are the parameters to determine the table sizes #self.load_scales = np.array([0.1, 0.25, 0.5, 1, 2, 4, 8]) self.load_scales = np.array([0.25, 1, 8]) #self.load_scales = np.array([0.25, 1]) - self.load = tech.spice["FF_in_cap"] + self.load = tech.spice["msflop_in_cap"] self.loads = self.load_scales*self.load debug.info(1,"Loads: {0}".format(self.loads)) @@ -50,9 +59,43 @@ class lib: self.slew = tech.spice["rise_time"] self.slews = self.slew_scales*self.slew debug.info(1,"Slews: {0}".format(self.slews)) - - debug.info(1,"Writing to {0}".format(libname)) - self.lib = open(libname, "w") + + + def create_corners(self): + """ Create corners for characterization. """ + # Get the corners from the options file + self.temperatures = OPTS.temperatures + self.supply_voltages = OPTS.supply_voltages + self.process_corners = OPTS.process_corners + + # Enumerate all possible corners + self.corners = [] + self.lib_files = [] + for proc in self.process_corners: + for temp in self.temperatures: + for volt in self.supply_voltages: + self.corner_name = "{0}_{1}_{2}V_{3}C".format(self.sram.name, + proc, + volt, + temp) + self.corner_name = self.corner_name.replace(".","") # Remove decimals + lib_name = self.out_dir+"{}.lib".format(self.corner_name) + + # A corner is a tuple of PVT + self.corners.append((proc, volt, temp)) + self.lib_files.append(lib_name) + + def characterize_corners(self): + """ Characterize the list of corners. """ + for (self.corner,lib_name) in zip(self.corners,self.lib_files): + debug.info(1,"Corner: " + str(self.corner)) + (self.process, self.voltage, self.temperature) = self.corner + self.lib = open(lib_name, "w") + debug.info(1,"Writing to {0}".format(lib_name)) + self.characterize() + + def characterize(self): + """ Characterize the current corner. """ self.write_header() @@ -68,7 +111,7 @@ class lib: def write_header(self): """ Write the header information """ - self.lib.write("library ({0}_lib)".format(self.name)) + self.lib.write("library ({0}_lib)".format(self.corner_name)) self.lib.write("{\n") self.lib.write(" delay_model : \"table_lookup\";\n") @@ -80,12 +123,12 @@ class lib: self.write_bus() - self.lib.write("cell ({0})".format(self.name)) + self.lib.write("cell ({0})".format(self.sram.name)) self.lib.write("{\n") self.lib.write(" memory(){ \n") self.lib.write(" type : ram;\n") - self.lib.write(" address_width : {0};\n".format(self.addr_size)) - self.lib.write(" word_width : {0};\n".format(self.word_size)) + self.lib.write(" address_width : {0};\n".format(self.sram.addr_size)) + self.lib.write(" word_width : {0};\n".format(self.sram.word_size)) self.lib.write(" }\n") self.lib.write(" interface_timing : true;\n") self.lib.write(" dont_use : true;\n") @@ -104,9 +147,9 @@ class lib: self.lib.write(" capacitive_load_unit(1 ,fF) ;\n") self.lib.write(" leakage_power_unit : \"1mW\" ;\n") self.lib.write(" pulling_resistance_unit :\"1kohm\" ;\n") - self.lib.write(" operating_conditions(TT){\n") - self.lib.write(" voltage : {0} ;\n".format(tech.spice["supply_voltage"])) - self.lib.write(" temperature : 25.000 ;\n") + self.lib.write(" operating_conditions({}){{\n".format(self.process)) + self.lib.write(" voltage : {} ;\n".format(self.voltage)) + self.lib.write(" temperature : {};\n".format(self.temperature)) self.lib.write(" }\n\n") def write_defaults(self): @@ -207,17 +250,17 @@ class lib: self.lib.write(" type (DATA){\n") self.lib.write(" base_type : array;\n") self.lib.write(" data_type : bit;\n") - self.lib.write(" bit_width : {0};\n".format(self.word_size)) + self.lib.write(" bit_width : {0};\n".format(self.sram.word_size)) self.lib.write(" bit_from : 0;\n") - self.lib.write(" bit_to : {0};\n".format(self.word_size - 1)) + self.lib.write(" bit_to : {0};\n".format(self.sram.word_size - 1)) self.lib.write(" }\n\n") self.lib.write(" type (ADDR){\n") self.lib.write(" base_type : array;\n") self.lib.write(" data_type : bit;\n") - self.lib.write(" bit_width : {0};\n".format(self.addr_size)) + self.lib.write(" bit_width : {0};\n".format(self.sram.addr_size)) self.lib.write(" bit_from : 0;\n") - self.lib.write(" bit_to : {0};\n".format(self.addr_size - 1)) + self.lib.write(" bit_to : {0};\n".format(self.sram.addr_size - 1)) self.lib.write(" }\n\n") @@ -261,7 +304,7 @@ class lib: self.lib.write(" bus(DATA){\n") self.lib.write(" bus_type : DATA; \n") self.lib.write(" direction : inout; \n") - self.lib.write(" max_capacitance : {0}; \n".format(8*tech.spice["FF_in_cap"])) + self.lib.write(" max_capacitance : {0}; \n".format(8*tech.spice["msflop_in_cap"])) self.lib.write(" three_state : \"!OEb & !clk\"; \n") self.lib.write(" memory_write(){ \n") self.lib.write(" address : ADDR; \n") @@ -270,7 +313,7 @@ class lib: self.lib.write(" memory_read(){ \n") self.lib.write(" address : ADDR; \n") self.lib.write(" }\n") - self.lib.write(" pin(DATA[{0}:0])".format(self.word_size - 1)) + self.lib.write(" pin(DATA[{0}:0])".format(self.sram.word_size - 1)) self.lib.write("{\n") self.lib.write(" internal_power(){\n") @@ -325,10 +368,10 @@ class lib: self.lib.write(" bus(ADDR){\n") self.lib.write(" bus_type : ADDR; \n") self.lib.write(" direction : input; \n") - self.lib.write(" capacitance : {0}; \n".format(tech.spice["FF_in_cap"])) + self.lib.write(" capacitance : {0}; \n".format(tech.spice["msflop_in_cap"])) self.lib.write(" max_transition : {0};\n".format(self.slews[-1])) self.lib.write(" fanout_load : 1.000000;\n") - self.lib.write(" pin(ADDR[{0}:0])".format(self.addr_size - 1)) + self.lib.write(" pin(ADDR[{0}:0])".format(self.sram.addr_size - 1)) self.lib.write("{\n") self.write_FF_setuphold() @@ -344,7 +387,7 @@ class lib: self.lib.write(" pin({0})".format(i)) self.lib.write("{\n") self.lib.write(" direction : input; \n") - self.lib.write(" capacitance : {0}; \n".format(tech.spice["FF_in_cap"])) + self.lib.write(" capacitance : {0}; \n".format(tech.spice["msflop_in_cap"])) self.write_FF_setuphold() self.lib.write(" }\n\n") @@ -357,7 +400,7 @@ class lib: self.lib.write(" pin(clk){\n") self.lib.write(" clock : true;\n") self.lib.write(" direction : input; \n") - self.lib.write(" capacitance : {0}; \n".format(tech.spice["FF_in_cap"])) + self.lib.write(" capacitance : {0}; \n".format(tech.spice["msflop_in_cap"])) min_pulse_width = ch.round_time(self.delay["min_period"])/2.0 min_period = ch.round_time(self.delay["min_period"]) self.lib.write(" timing(){ \n") @@ -389,12 +432,12 @@ class lib: try: self.d except AttributeError: - self.d = delay.delay(self.sram, self.sim_sp_file) + self.d = delay.delay(self.sram, self.sim_sp_file, self.corner) if self.use_model: self.delay = self.d.analytical_model(self.sram,self.slews,self.loads) else: - probe_address = "1" * self.addr_size - probe_data = self.word_size - 1 + probe_address = "1" * self.sram.addr_size + probe_data = self.sram.word_size - 1 # We must trim based on a specific address and data bit if OPTS.trim_netlist: self.trimsp.trim(probe_address,probe_data) @@ -406,7 +449,7 @@ class lib: try: self.sh except AttributeError: - self.sh = setup_hold.setup_hold() + self.sh = setup_hold.setup_hold(self.corner) if self.use_model: self.times = self.sh.analytical_model(self.slews,self.loads) else: diff --git a/compiler/characterizer/setup_hold.py b/compiler/characterizer/setup_hold.py index 919bb9b9..5a3bfdb4 100644 --- a/compiler/characterizer/setup_hold.py +++ b/compiler/characterizer/setup_hold.py @@ -13,18 +13,23 @@ class setup_hold(): (Bisection Methodology) """ - def __init__(self): + def __init__(self, corner): # This must match the spice model order self.pins = ["data", "dout", "dout_bar", "clk", "vdd", "gnd"] self.model_name = "ms_flop" self.model_location = OPTS.openram_tech + "sp_lib/ms_flop.sp" self.period = tech.spice["feasible_period"] - self.vdd = tech.spice["supply_voltage"] - self.gnd = tech.spice["gnd_voltage"] debug.info(2,"Feasible period from technology file: {0} ".format(self.period)) + self.set_corner(corner) + + def set_corner(self,corner): + """ Set the corner values """ + self.corner = corner + (self.process, self.vdd_voltage, self.temperature) = corner + self.gnd_voltage = 0 def write_stimulus(self, mode, target_time, correct_value): @@ -33,14 +38,14 @@ class setup_hold(): # creates and opens the stimulus file for writing temp_stim = OPTS.openram_temp + "stim.sp" self.sf = open(temp_stim, "w") + self.stim = stimuli.stimuli(self.sf, self.corner) self.write_header(correct_value) # instantiate the master-slave d-flip-flop - self.sf.write("* Instantiation of the Master-Slave D-flip-flop\n") - stimuli.inst_model(stim_file=self.sf, - pins=self.pins, - model_name=self.model_name) + self.sf.write("\n* Instantiation of the Master-Slave D-flip-flop\n") + self.stim.inst_model(pins=self.pins, + model_name=self.model_name) self.write_data(mode=mode, target_time=target_time, @@ -52,22 +57,20 @@ class setup_hold(): correct_value=correct_value) - stimuli.write_control(self.sf,4*self.period) + self.stim.write_control(4*self.period) self.sf.close() def write_header(self, correct_value): """ Write the header file with all the models and the power supplies. """ - self.sf.write("* Stimulus for setup/hold: data {0} period {1}n\n".format(correct_value, self.period)) + self.sf.write("\n* Stimulus for setup/hold: data {0} period {1}n\n".format(correct_value, self.period)) # include files in stimulus file - self.model_list = tech.spice["fet_models"] + [self.model_location] - stimuli.write_include(stim_file=self.sf, - models=self.model_list) + self.stim.write_include(self.model_location) # add vdd/gnd statements - self.sf.write("* Global Power Supplies\n") - stimuli.write_supply(self.sf) + self.sf.write("\n* Global Power Supplies\n") + self.stim.write_supply() def write_data(self, mode, target_time, correct_value): @@ -76,8 +79,8 @@ class setup_hold(): characterization. """ - self.sf.write("* Generation of the data and clk signals\n") - incorrect_value = stimuli.get_inverse_value(correct_value) + self.sf.write("\n* Generation of the data and clk signals\n") + incorrect_value = self.stim.get_inverse_value(correct_value) if mode=="HOLD": init_value = incorrect_value start_value = correct_value @@ -87,29 +90,27 @@ class setup_hold(): start_value = incorrect_value end_value = correct_value - stimuli.gen_pwl(stim_file=self.sf, - sig_name="data", - clk_times=[self.period, target_time], - data_values=[init_value, start_value, end_value], - period=target_time, - slew=self.constrained_input_slew, - setup=0) + self.stim.gen_pwl(sig_name="data", + clk_times=[0, self.period, target_time], + data_values=[init_value, start_value, end_value], + period=target_time, + slew=self.constrained_input_slew, + setup=0) def write_clock(self): """ Create the clock signal for setup/hold analysis. First period initializes the FF while the second is used for characterization.""" - stimuli.gen_pwl(stim_file=self.sf, - sig_name="clk", - # initial clk edge is right after the 0 time to initialize a flop - # without using .IC on an internal node. - # Return input to value after one period. - # The second pulse is the characterization one at 2*period - clk_times=[0.1*self.period,self.period,2*self.period], - data_values=[0, 1, 0, 1], - period=2*self.period, - slew=self.constrained_input_slew, - setup=0) + self.stim.gen_pwl(sig_name="clk", + # initial clk edge is right after the 0 time to initialize a flop + # without using .IC on an internal node. + # Return input to value after one period. + # The second pulse is the characterization one at 2*period + clk_times=[0, 0.1*self.period,self.period,2*self.period], + data_values=[0, 1, 0, 1], + period=2*self.period, + slew=self.constrained_input_slew, + setup=0) @@ -132,33 +133,33 @@ class setup_hold(): din_rise_or_fall = "RISE" - self.sf.write("* Measure statements for pass/fail verification\n") + self.sf.write("\n* Measure statements for pass/fail verification\n") trig_name = "clk" targ_name = "dout" - trig_val = targ_val = 0.5 * self.vdd + trig_val = targ_val = 0.5 * self.vdd_voltage # Start triggers right before the clock edge at 2*period - stimuli.gen_meas_delay(stim_file=self.sf, - meas_name="clk2q_delay", - trig_name=trig_name, - targ_name=targ_name, - trig_val=trig_val, - targ_val=targ_val, - trig_dir="RISE", - targ_dir=dout_rise_or_fall, - td=1.9*self.period) - + self.stim.gen_meas_delay(meas_name="clk2q_delay", + trig_name=trig_name, + targ_name=targ_name, + trig_val=trig_val, + targ_val=targ_val, + trig_dir="RISE", + targ_dir=dout_rise_or_fall, + trig_td=1.9*self.period, + targ_td=1.9*self.period) + targ_name = "data" # Start triggers right after initialize value is returned to normal # at one period - stimuli.gen_meas_delay(stim_file=self.sf, - meas_name="setup_hold_time", - trig_name=trig_name, - targ_name=targ_name, - trig_val=trig_val, - targ_val=targ_val, - trig_dir="RISE", - targ_dir=din_rise_or_fall, - td=1.2*self.period) + self.stim.gen_meas_delay(meas_name="setup_hold_time", + trig_name=trig_name, + targ_name=targ_name, + trig_val=trig_val, + targ_val=targ_val, + trig_dir="RISE", + targ_dir=din_rise_or_fall, + trig_td=1.2*self.period, + targ_td=1.2*self.period) @@ -184,7 +185,7 @@ class setup_hold(): self.write_stimulus(mode=mode, target_time=feasible_bound, correct_value=correct_value) - stimuli.run_sim() + self.stim.run_sim() ideal_clk_to_q = ch.convert_to_float(ch.parse_output("timing", "clk2q_delay")) setuphold_time = ch.convert_to_float(ch.parse_output("timing", "setup_hold_time")) debug.info(2,"*** {0} CHECK: {1} Ideal Clk-to-Q: {2} Setup/Hold: {3}".format(mode, correct_value,ideal_clk_to_q,setuphold_time)) @@ -217,7 +218,7 @@ class setup_hold(): feasible_bound)) - stimuli.run_sim() + self.stim.run_sim() clk_to_q = ch.convert_to_float(ch.parse_output("timing", "clk2q_delay")) setuphold_time = ch.convert_to_float(ch.parse_output("timing", "setup_hold_time")) if type(clk_to_q)==float and (clk_to_q<1.1*ideal_clk_to_q) and type(setuphold_time)==float: diff --git a/compiler/characterizer/stimuli.py b/compiler/characterizer/stimuli.py index 6cba2015..297d9f37 100644 --- a/compiler/characterizer/stimuli.py +++ b/compiler/characterizer/stimuli.py @@ -1,7 +1,7 @@ """ -This file generates the test structure and stimulus for an sram -simulation. There are various functions that can be be used to -generate stimulus for other simulations as well. +This file generates simple spice cards for simulation. There are +various functions that can be be used to generate stimulus for other +simulations as well. """ import tech @@ -12,316 +12,301 @@ import sys import numpy as np from globals import OPTS -vdd_voltage = tech.spice["supply_voltage"] -gnd_voltage = tech.spice["gnd_voltage"] -vdd_name = tech.spice["vdd_name"] -gnd_name = tech.spice["gnd_name"] -pmos_name = tech.spice["pmos_name"] -nmos_name = tech.spice["nmos_name"] -tx_width = tech.spice["minwidth_tx"] -tx_length = tech.spice["channel"] -def inst_sram(stim_file, abits, dbits, sram_name): - """function to instatiate the sram subckt""" - stim_file.write("Xsram ") - for i in range(dbits): - stim_file.write("D[{0}] ".format(i)) - for i in range(abits): - stim_file.write("A[{0}] ".format(i)) - for i in tech.spice["control_signals"]: - stim_file.write("{0} ".format(i)) - stim_file.write("{0} ".format(tech.spice["clk"])) - stim_file.write("{0} {1} ".format(vdd_name, gnd_name)) - stim_file.write("{0}\n\n".format(sram_name)) +class stimuli(): + """ Class for providing stimuli functions """ + def __init__(self, stim_file, corner): + self.vdd_name = tech.spice["vdd_name"] + self.gnd_name = tech.spice["gnd_name"] + self.pmos_name = tech.spice["pmos"] + self.nmos_name = tech.spice["nmos"] + self.tx_width = tech.spice["minwidth_tx"] + self.tx_length = tech.spice["channel"] -def inst_model(stim_file, pins, model_name): - """function to instantiate a model""" - stim_file.write("X{0} ".format(model_name)) - for pin in pins: - stim_file.write("{0} ".format(pin)) - stim_file.write("{0}\n".format(model_name)) - - -def create_inverter(stim_file, size=1, beta=2.5): - """Generates inverter for the top level signals (only for sim purposes)""" - stim_file.write(".SUBCKT test_inv in out {0} {1}\n".format(vdd_name, gnd_name)) - stim_file.write("mpinv out in {0} {0} {1} w={2}u l={3}u\n".format(vdd_name, - pmos_name, - beta * size * tx_width, - tx_length)) - stim_file.write("mninv out in {0} {0} {1} w={2}u l={3}u\n".format(gnd_name, - nmos_name, - size * tx_width, - tx_length)) - stim_file.write(".ENDS test_inv\n") - - -def create_buffer(stim_file, buffer_name, size=[1,3], beta=2.5): - """Generates buffer for top level signals (only for sim - purposes). Size is pair for PMOS, NMOS width multiple. It includes - a beta of 3.""" - - stim_file.write(".SUBCKT test_{2} in out {0} {1}\n".format(vdd_name, - gnd_name, - buffer_name)) - stim_file.write("mpinv1 out_inv in {0} {0} {1} w={2}u l={3}u\n".format(vdd_name, - pmos_name, - beta * size[0] * tx_width, - tx_length)) - stim_file.write("mninv1 out_inv in {0} {0} {1} w={2}u l={3}u\n".format(gnd_name, - nmos_name, - size[0] * tx_width, - tx_length)) - stim_file.write("mpinv2 out out_inv {0} {0} {1} w={2}u l={3}u\n".format(vdd_name, - pmos_name, - beta * size[1] * tx_width, - tx_length)) - stim_file.write("mninv2 out out_inv {0} {0} {1} w={2}u l={3}u\n".format(gnd_name, - nmos_name, - size[1] * tx_width, - tx_length)) - stim_file.write(".ENDS test_{0}\n\n".format(buffer_name)) - - -def inst_buffer(stim_file, buffer_name, signal_list): - """Adds buffers to each top level signal that is in signal_list (only for sim purposes)""" - for signal in signal_list: - stim_file.write("X{0}_buffer {0} {0}_buf {1} {2} test_{3}\n".format(signal, - "test"+vdd_name, - "test"+gnd_name, - buffer_name)) - - -def inst_inverter(stim_file, signal_list): - """Adds inv for each signal that needs its inverted version (only for sim purposes)""" - for signal in signal_list: - stim_file.write("X{0}_inv {0} {0}_inv {1} {2} test_inv\n".format(signal, - "test"+vdd_name, - "test"+gnd_name)) - - -def inst_accesstx(stim_file, dbits): - """Adds transmission gate for inputs to data-bus (only for sim purposes)""" - stim_file.write("* Tx Pin-list: Drain Gate Source Body\n") - for i in range(dbits): - pmos_access_string="mp{0} DATA[{0}] acc_en D[{0}] {1} {2} w={3}u l={4}u\n" - stim_file.write(pmos_access_string.format(i, - "test"+vdd_name, - pmos_name, - 2 * tx_width, - tx_length)) - nmos_access_string="mn{0} DATA[{0}] acc_en_inv D[{0}] {1} {2} w={3}u l={4}u\n" - stim_file.write(nmos_access_string.format(i, - "test"+gnd_name, - nmos_name, - 2 * tx_width, - tx_length)) - -def gen_pulse(stim_file, sig_name, v1=gnd_voltage, v2=vdd_voltage, offset=0, period=1, t_rise=0, t_fall=0): - """Generates a periodic signal with 50% duty cycle and slew rates. Period is measured - from 50% to 50%.""" - pulse_string="V{0} {0} 0 PULSE ({1} {2} {3}n {4}n {5}n {6}n {7}n)\n" - stim_file.write(pulse_string.format(sig_name, - v1, - v2, - offset, - t_rise, - t_fall, - 0.5*period-0.5*t_rise-0.5*t_fall, - period)) - - -def gen_pwl(stim_file, sig_name, clk_times, data_values, period, slew, setup): - # the initial value is not a clock time - debug.check(len(clk_times)+1==len(data_values),"Clock and data value lengths don't match.") - # shift signal times earlier for setup time - times = np.array(clk_times) - setup*period - values = np.array(data_values) * vdd_voltage - half_slew = 0.5 * slew - stim_file.write("V{0} {0} 0 PWL (0n {1}v ".format(sig_name, values[0])) - for i in range(len(times)): - stim_file.write("{0}n {1}v {2}n {3}v ".format(times[i]-half_slew, - values[i], - times[i]+half_slew, - values[i+1])) - stim_file.write(")\n") - -def gen_data(stim_file, clk_times, sig_name, period, slew): - """Generates the PWL data inputs for a simulation timing test.""" - # values for NOP, W1, W0, W1, R0, W1, W0, R1, NOP - # we are asserting the opposite value on the other side of the tx gate during - # the read to be "worst case". Otherwise, it can actually assist the read. - values = [0, 1, 0, 1, 1, 1, 0, 0, 0 ] - gen_pwl(stim_file, sig_name, clk_times, values, period, slew, 0.05) - - -def gen_addr(stim_file, clk_times, addr, period, slew): - """Generates the address inputs for a simulation timing test. - One cycle is different to clear the bus - """ - - zero_values = [0, 0, 0, 1, 0, 0, 1, 0, 0 ] - ones_values = [1, 1, 1, 0, 1, 1, 0, 1, 1 ] - - for i in range(len(addr)): - sig_name = "A[{0}]".format(i) - if addr[i]=="1": - gen_pwl(stim_file, sig_name, clk_times, ones_values, period, slew, 0.05) - else: - gen_pwl(stim_file, sig_name, clk_times, zero_values, period, slew, 0.05) - -def gen_constant(stim_file, sig_name, v_val): - """Generates a constant signal with reference voltage and the voltage value""" - stim_file.write("V{0} {0} 0 DC {1}\n".format(sig_name, v_val)) - -def gen_csb(stim_file, clk_times, period, slew): - """ Generates the PWL CSb signal""" - # values for NOP, W1, W0, W1, R0, W1, W0, R1, NOP - values = [1, 0, 0, 0, 0, 0, 0, 0, 1] - gen_pwl(stim_file, "csb", clk_times, values, period, slew, 0.05) - -def gen_web(stim_file, clk_times, period, slew): - """ Generates the PWL WEb signal""" - # values for NOP, W1, W0, W1, R0, W1, W0, R1, NOP - values = [1, 0, 0, 0, 1, 0, 0, 1, 1] - gen_pwl(stim_file, "web", clk_times, values, period, slew, 0.05) - - values = [1, 0, 0, 0, 1, 0, 0, 1, 1] - gen_pwl(stim_file, "acc_en", clk_times, values, period, slew, 0) - values = [0, 1, 1, 1, 0, 1, 1, 0, 0] - gen_pwl(stim_file, "acc_en_inv", clk_times, values, period, slew, 0) - -def gen_oeb(stim_file, clk_times, period, slew): - """ Generates the PWL WEb signal""" - # values for NOP, W1, W0, W1, R0, W1, W0, R1, NOP - values = [1, 1, 1, 1, 0, 1, 1, 0, 1] - gen_pwl(stim_file, "oeb", clk_times, values, period, slew, 0.05) - - - - -def get_inverse_voltage(value): - if value > 0.5*vdd_voltage: - return gnd_voltage - elif value <= 0.5*vdd_voltage: - return vdd_voltage - else: - debug.error("Invalid value to get an inverse of: {0}".format(value)) - -def get_inverse_value(value): - if value > 0.5: - return 0 - elif value <= 0.5: - return 1 - else: - debug.error("Invalid value to get an inverse of: {0}".format(value)) + self.sf = stim_file + (self.process, self.voltage, self.temperature) = corner + self.device_models = tech.spice["fet_models"][self.process] -def gen_meas_delay(stim_file, meas_name, trig_name, targ_name, trig_val, targ_val, trig_dir, targ_dir, td): - """Creates the .meas statement for the measurement of delay""" - measure_string=".meas tran {0} TRIG v({1}) VAL={2} {3}=1 TD={7}n TARG v({4}) VAL={5} {6}=1 TD={7}n\n\n" - stim_file.write(measure_string.format(meas_name, - trig_name, - trig_val, - trig_dir, - targ_name, - targ_val, - targ_dir, - td)) -def gen_meas_power(stim_file, meas_name, t_initial, t_final): - """Creates the .meas statement for the measurement of avg power""" - # power mea cmd is different in different spice: - if OPTS.spice_name == "hspice": - power_exp = "power" - else: - power_exp = "par('(-1*v(" + str(vdd_name) + ")*I(v" + str(vdd_name) + "))')" - stim_file.write(".meas tran {0} avg {1} from={2}n to={3}n\n\n".format(meas_name, - power_exp, - t_initial, - t_final)) - stim_file.write("\n") - -def write_control(stim_file, end_time): - # UIC is needed for ngspice to converge - stim_file.write(".TRAN 5p {0}n UIC\n".format(end_time)) - stim_file.write(".OPTIONS POST=1 RUNLVL=4 PROBE\n") - # create plots for all signals - stim_file.write("* probe is used for hspice/xa, while plot is used in ngspice\n") - if OPTS.debug_level>0: - if OPTS.spice_name in ["hspice","xa"]: - stim_file.write(".probe V(*)\n") - else: - stim_file.write(".plot V(*)\n") - else: - stim_file.write("*.probe V(*)\n") - stim_file.write("*.plot V(*)\n") - - # end the stimulus file - stim_file.write(".end\n\n") + def inst_sram(self, abits, dbits, sram_name): + """ Function to instatiate an SRAM subckt. """ + self.sf.write("Xsram ") + for i in range(dbits): + self.sf.write("D[{0}] ".format(i)) + for i in range(abits): + self.sf.write("A[{0}] ".format(i)) + for i in tech.spice["control_signals"]: + self.sf.write("{0} ".format(i)) + self.sf.write("{0} ".format(tech.spice["clk"])) + self.sf.write("{0} {1} ".format(self.vdd_name, self.gnd_name)) + self.sf.write("{0}\n".format(sram_name)) -def write_include(stim_file, models): - """Writes include statements, inputs are lists of model files""" - for item in list(models): - stim_file.write(".include \"{0}\"\n\n".format(item)) + def inst_model(self, pins, model_name): + """ Function to instantiate a generic model with a set of pins """ + self.sf.write("X{0} ".format(model_name)) + for pin in pins: + self.sf.write("{0} ".format(pin)) + self.sf.write("{0}\n".format(model_name)) -def write_supply(stim_file): - """Writes supply voltage statements""" - stim_file.write("V{0} {0} 0.0 {1}\n".format(vdd_name, vdd_voltage)) - stim_file.write("V{0} {0} 0.0 {1}\n".format(gnd_name, gnd_voltage)) - # This is for the test power supply - stim_file.write("V{0} {0} 0.0 {1}\n".format("test"+vdd_name, vdd_voltage)) - stim_file.write("V{0} {0} 0.0 {1}\n\n".format("test"+gnd_name, gnd_voltage)) + def create_inverter(self, size=1, beta=2.5): + """ Generates inverter for the top level signals (only for sim purposes) """ + self.sf.write(".SUBCKT test_inv in out {0} {1}\n".format(self.vdd_name, self.gnd_name)) + self.sf.write("mpinv out in {0} {0} {1} w={2}u l={3}u\n".format(self.vdd_name, + self.pmos_name, + beta * size * self.tx_width, + self.tx_length)) + self.sf.write("mninv out in {0} {0} {1} w={2}u l={3}u\n".format(self.gnd_name, + self.nmos_name, + size * self.tx_width, + self.tx_length)) + self.sf.write(".ENDS test_inv\n") -def run_sim(): - """Run hspice in batch mode and output rawfile to parse.""" - temp_stim = "{0}stim.sp".format(OPTS.openram_temp) - import datetime - start_time = datetime.datetime.now() - debug.check(OPTS.spice_exe!="","No spice simulator has been found.") - - if OPTS.spice_name == "xa": - # Output the xa configurations here. FIXME: Move this to write it once. - xa_cfg = open("{}xa.cfg".format(OPTS.openram_temp), "w") - xa_cfg.write("set_sim_level -level 7\n") - xa_cfg.write("set_powernet_level 7 -node vdd\n") - xa_cfg.close() - cmd = "{0} {1} -c {2}xa.cfg -o {2}xa -mt 20".format(OPTS.spice_exe, - temp_stim, - OPTS.openram_temp) - valid_retcode=0 - elif OPTS.spice_name == "hspice": - # TODO: Should make multithreading parameter a configuration option - cmd = "{0} -mt 2 -i {1} -o {2}timing".format(OPTS.spice_exe, - temp_stim, - OPTS.openram_temp) - valid_retcode=0 - else: - cmd = "{0} -b -o {2}timing.lis {1}".format(OPTS.spice_exe, - temp_stim, - OPTS.openram_temp) - # for some reason, ngspice-25 returns 1 when it only has acceptable warnings - valid_retcode=1 + def create_buffer(self, buffer_name, size=[1,3], beta=2.5): + """ + Generates buffer for top level signals (only for sim + purposes). Size is pair for PMOS, NMOS width multiple. + """ + + self.sf.write(".SUBCKT test_{2} in out {0} {1}\n".format(self.vdd_name, + self.gnd_name, + buffer_name)) + self.sf.write("mpinv1 out_inv in {0} {0} {1} w={2}u l={3}u\n".format(self.vdd_name, + self.pmos_name, + beta * size[0] * self.tx_width, + self.tx_length)) + self.sf.write("mninv1 out_inv in {0} {0} {1} w={2}u l={3}u\n".format(self.gnd_name, + self.nmos_name, + size[0] * self.tx_width, + self.tx_length)) + self.sf.write("mpinv2 out out_inv {0} {0} {1} w={2}u l={3}u\n".format(self.vdd_name, + self.pmos_name, + beta * size[1] * self.tx_width, + self.tx_length)) + self.sf.write("mninv2 out out_inv {0} {0} {1} w={2}u l={3}u\n".format(self.gnd_name, + self.nmos_name, + size[1] * self.tx_width, + self.tx_length)) + self.sf.write(".ENDS test_{0}\n\n".format(buffer_name)) + + + def inst_buffer(self, buffer_name, signal_list): + """ Adds buffers to each top level signal that is in signal_list (only for sim purposes) """ + for signal in signal_list: + self.sf.write("X{0}_buffer {0} {0}_buf {1} {2} test_{3}\n".format(signal, + "test"+self.vdd_name, + "test"+self.gnd_name, + buffer_name)) + + + def inst_inverter(self, signal_list): + """ Adds inv for each signal that needs its inverted version (only for sim purposes) """ + for signal in signal_list: + self.sf.write("X{0}_inv {0} {0}_inv {1} {2} test_inv\n".format(signal, + "test"+self.vdd_name, + "test"+self.gnd_name)) - spice_stdout = open("{0}spice_stdout.log".format(OPTS.openram_temp), 'w') - spice_stderr = open("{0}spice_stderr.log".format(OPTS.openram_temp), 'w') + def inst_accesstx(self, dbits): + """ Adds transmission gate for inputs to data-bus (only for sim purposes) """ + self.sf.write("* Tx Pin-list: Drain Gate Source Body\n") + for i in range(dbits): + pmos_access_string="mp{0} DATA[{0}] acc_en D[{0}] {1} {2} w={3}u l={4}u\n" + self.sf.write(pmos_access_string.format(i, + "test"+self.vdd_name, + self.pmos_name, + 2 * self.tx_width, + self.tx_length)) + nmos_access_string="mn{0} DATA[{0}] acc_en_inv D[{0}] {1} {2} w={3}u l={4}u\n" + self.sf.write(nmos_access_string.format(i, + "test"+self.gnd_name, + self.nmos_name, + 2 * self.tx_width, + self.tx_length)) - debug.info(3, cmd) - retcode = subprocess.call(cmd, stdout=spice_stdout, stderr=spice_stderr, shell=True) + def gen_pulse(self, sig_name, v1, v2, offset, period, t_rise, t_fall): + """ + Generates a periodic signal with 50% duty cycle and slew rates. Period is measured + from 50% to 50%. + """ + self.sf.write("* PULSE: period={0}\n".format(period)) + pulse_string="V{0} {0} 0 PULSE ({1} {2} {3}n {4}n {5}n {6}n {7}n)\n" + self.sf.write(pulse_string.format(sig_name, + v1, + v2, + offset, + t_rise, + t_fall, + 0.5*period-0.5*t_rise-0.5*t_fall, + period)) - spice_stdout.close() - spice_stderr.close() + + def gen_pwl(self, sig_name, clk_times, data_values, period, slew, setup): + """ + Generate a PWL stimulus given a signal name and data values at each period. + Automatically creates slews and ensures each data occurs a setup before the clock + edge. The first clk_time should be 0 and is the initial time that corresponds + to the initial value. + """ + # the initial value is not a clock time + debug.check(len(clk_times)==len(data_values),"Clock and data value lengths don't match.") - if (retcode > valid_retcode): - debug.error("Spice simulation error: " + cmd, -1) - else: - end_time = datetime.datetime.now() - delta_time = round((end_time-start_time).total_seconds(),1) - debug.info(2,"*** Spice: {} seconds".format(delta_time)) + # shift signal times earlier for setup time + times = np.array(clk_times) - setup*period + values = np.array(data_values) * self.voltage + half_slew = 0.5 * slew + self.sf.write("* (time, data): {}\n".format(zip(clk_times, data_values))) + self.sf.write("V{0} {0} 0 PWL (0n {1}v ".format(sig_name, values[0])) + for i in range(1,len(times)): + self.sf.write("{0}n {1}v {2}n {3}v ".format(times[i]-half_slew, + values[i-1], + times[i]+half_slew, + values[i])) + self.sf.write(")\n") + + def gen_constant(self, sig_name, v_val): + """ Generates a constant signal with reference voltage and the voltage value """ + self.sf.write("V{0} {0} 0 DC {1}\n".format(sig_name, v_val)) + + def get_inverse_voltage(self, value): + if value > 0.5*self.voltage: + return 0 + elif value <= 0.5*self.voltage: + return self.voltage + else: + debug.error("Invalid value to get an inverse of: {0}".format(value)) + + def get_inverse_value(self, value): + if value > 0.5: + return 0 + elif value <= 0.5: + return 1 + else: + debug.error("Invalid value to get an inverse of: {0}".format(value)) + + + def gen_meas_delay(self, meas_name, trig_name, targ_name, trig_val, targ_val, trig_dir, targ_dir, trig_td, targ_td): + """ Creates the .meas statement for the measurement of delay """ + measure_string=".meas tran {0} TRIG v({1}) VAL={2} {3}=1 TD={4}n TARG v({5}) VAL={6} {7}=1 TD={8}n\n\n" + self.sf.write(measure_string.format(meas_name, + trig_name, + trig_val, + trig_dir, + trig_td, + targ_name, + targ_val, + targ_dir, + targ_td)) + + def gen_meas_power(self, meas_name, t_initial, t_final): + """ Creates the .meas statement for the measurement of avg power """ + # power mea cmd is different in different spice: + if OPTS.spice_name == "hspice": + power_exp = "power" + else: + power_exp = "par('(-1*v(" + str(self.vdd_name) + ")*I(v" + str(self.vdd_name) + "))')" + self.sf.write(".meas tran {0} avg {1} from={2}n to={3}n\n\n".format(meas_name, + power_exp, + t_initial, + t_final)) + + def write_control(self, end_time): + """ Write the control cards to run and end the simulation """ + # UIC is needed for ngspice to converge + self.sf.write(".TRAN 5p {0}n UIC\n".format(end_time)) + if OPTS.spice_name == "ngspice": + # ngspice sometimes has convergence problems if not using gear method + # which is more accurate, but slower than the default trapezoid method + # Do not remove this or it may not converge due to some "pa_00" nodes + # unless you figure out what these are. + self.sf.write(".OPTIONS POST=1 RUNLVL=4 PROBE method=gear TEMP={}\n".format(self.temperature)) + else: + self.sf.write(".OPTIONS POST=1 RUNLVL=4 PROBE TEMP={}\n".format(self.temperature)) + + # create plots for all signals + self.sf.write("* probe is used for hspice/xa, while plot is used in ngspice\n") + if OPTS.debug_level>0: + if OPTS.spice_name in ["hspice","xa"]: + self.sf.write(".probe V(*)\n") + else: + self.sf.write(".plot V(*)\n") + else: + self.sf.write("*.probe V(*)\n") + self.sf.write("*.plot V(*)\n") + + # end the stimulus file + self.sf.write(".end\n\n") + + + def write_include(self, circuit): + """Writes include statements, inputs are lists of model files""" + includes = self.device_models + [circuit] + self.sf.write("* {} process corner\n".format(self.process)) + for item in list(includes): + if os.path.isfile(item): + self.sf.write(".include \"{0}\"\n".format(item)) + else: + debug.error("Could not find spice model: {0}\nSet SPICE_MODEL_DIR to over-ride path.\n".format(item)) + + + def write_supply(self): + """ Writes supply voltage statements """ + self.sf.write("V{0} {0} 0.0 {1}\n".format(self.vdd_name, self.voltage)) + self.sf.write("V{0} {0} 0.0 {1}\n".format(self.gnd_name, 0)) + # This is for the test power supply + self.sf.write("V{0} {0} 0.0 {1}\n".format("test"+self.vdd_name, self.voltage)) + self.sf.write("V{0} {0} 0.0 {1}\n".format("test"+self.gnd_name, 0)) + + + def run_sim(self): + """ Run hspice in batch mode and output rawfile to parse. """ + temp_stim = "{0}stim.sp".format(OPTS.openram_temp) + import datetime + start_time = datetime.datetime.now() + debug.check(OPTS.spice_exe!="","No spice simulator has been found.") + + if OPTS.spice_name == "xa": + # Output the xa configurations here. FIXME: Move this to write it once. + xa_cfg = open("{}xa.cfg".format(OPTS.openram_temp), "w") + xa_cfg.write("set_sim_level -level 7\n") + xa_cfg.write("set_powernet_level 7 -node vdd\n") + xa_cfg.close() + cmd = "{0} {1} -c {2}xa.cfg -o {2}xa -mt 2".format(OPTS.spice_exe, + temp_stim, + OPTS.openram_temp) + valid_retcode=0 + elif OPTS.spice_name == "hspice": + # TODO: Should make multithreading parameter a configuration option + cmd = "{0} -mt 2 -i {1} -o {2}timing".format(OPTS.spice_exe, + temp_stim, + OPTS.openram_temp) + valid_retcode=0 + else: + cmd = "{0} -b -o {2}timing.lis {1}".format(OPTS.spice_exe, + temp_stim, + OPTS.openram_temp) + # for some reason, ngspice-25 returns 1 when it only has acceptable warnings + valid_retcode=1 + + + spice_stdout = open("{0}spice_stdout.log".format(OPTS.openram_temp), 'w') + spice_stderr = open("{0}spice_stderr.log".format(OPTS.openram_temp), 'w') + + debug.info(3, cmd) + retcode = subprocess.call(cmd, stdout=spice_stdout, stderr=spice_stderr, shell=True) + + spice_stdout.close() + spice_stderr.close() + + if (retcode > valid_retcode): + debug.error("Spice simulation error: " + cmd, -1) + else: + end_time = datetime.datetime.now() + delta_time = round((end_time-start_time).total_seconds(),1) + debug.info(2,"*** Spice: {} seconds".format(delta_time)) diff --git a/compiler/characterizer/trim_spice.py b/compiler/characterizer/trim_spice.py index a5025d60..ead653b9 100644 --- a/compiler/characterizer/trim_spice.py +++ b/compiler/characterizer/trim_spice.py @@ -45,27 +45,38 @@ class trim_spice(): # Always start fresh if we do multiple reductions self.sp_buffer = self.spice - - # Find the row and column indices for the removals - # Convert address froms tring to int - address = int(address,2) - array_row = address >> self.col_addr_size - # Which word in the array (0 if only one word) - if self.col_addr_size>0: - lower_mask = int(self.col_addr_size-1) - lower_address = address & lower_mask - else: - lower_address=0 - # Which bit in the array - array_bit = lower_address*self.word_size + data_bit + # Split up the address and convert to an int + wl_address = int(address[self.col_addr_size:],2) + if self.col_addr_size>1: + col_address = int(address[0:self.col_addr_size],2) + else: + col_address = 0 # 1. Keep cells in the bitcell array based on WL and BL - wl_name = "wl[{}]".format(array_row) - bl_name = "bl[{}]".format(array_bit) + wl_name = "wl[{}]".format(wl_address) + bl_name = "bl[{}]".format(self.words_per_row*data_bit + col_address) + + # Prepend info about the trimming + addr_msg = "Keeping {} address".format(address) + self.sp_buffer.insert(0, "* "+addr_msg) + debug.info(1,addr_msg) + data_msg = "Keeping {} data bit".format(data_bit) + self.sp_buffer.insert(0, "* "+data_msg) + debug.info(1,data_msg) + bl_msg = "Keeping {} (trimming other BLs)".format(bl_name) + wl_msg = "Keeping {} (trimming other WLs)".format(wl_name) + self.sp_buffer.insert(0, "* "+bl_msg) + debug.info(1,bl_msg) + self.sp_buffer.insert(0, "* "+wl_msg) + debug.info(1,wl_msg) + self.sp_buffer.insert(0, "* It should NOT be used for LVS!!") + self.sp_buffer.insert(0, "* WARNING: This is a TRIMMED NETLIST.") + self.remove_insts("bitcell_array",[wl_name,bl_name]) # 2. Keep sense amps basd on BL - self.remove_insts("sense_amp_array",[bl_name]) + # FIXME: The bit lines are not indexed the same in sense_amp_array + #self.remove_insts("sense_amp_array",[bl_name]) # 3. Keep column muxes basd on BL self.remove_insts("column_mux_array",[bl_name]) diff --git a/compiler/example_config_freepdk45.py b/compiler/example_config_freepdk45.py index cd8a17b8..9366abcb 100644 --- a/compiler/example_config_freepdk45.py +++ b/compiler/example_config_freepdk45.py @@ -1,8 +1,11 @@ word_size = 2 -num_words = 16 +num_words = 128 num_banks = 1 tech_name = "freepdk45" +process_corners = ["TT"] +supply_voltages = [1.0] +temperatures = [25] output_path = "temp" output_name = "sram_2_16_1_freepdk45" diff --git a/compiler/example_config_scn3me_subm.py b/compiler/example_config_scn3me_subm.py index 1145c5b2..491fa4d2 100644 --- a/compiler/example_config_scn3me_subm.py +++ b/compiler/example_config_scn3me_subm.py @@ -3,6 +3,10 @@ num_words = 16 num_banks = 1 tech_name = "scn3me_subm" +process_corners = ["TT"] +supply_voltages = [ 5.0 ] +temperatures = [ 25 ] + output_path = "temp" output_name = "sram_2_16_1_scn3me_subm" diff --git a/compiler/globals.py b/compiler/globals.py index b0a81be5..4023f927 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -11,20 +11,11 @@ import sys import re import importlib -# Current version of OpenRAM. -VERSION = "1.01" - USAGE = "Usage: openram.py [options] \nUse -h for help.\n" # Anonymous object that will be the options OPTS = options.options() -# check that we are not using version 3 and at least 2.7 -major_python_version = sys.version_info.major -minor_python_version = sys.version_info.minor -if not (major_python_version == 2 and minor_python_version >= 7): - debug.error("Python 2.7 is required.",-1) - def parse_args(): """ Parse the optional arguments for OpenRAM """ @@ -39,8 +30,6 @@ def parse_args(): help="Output file(s) location"), optparse.make_option("-n", "--nocheck", action="store_false", help="Disable inline LVS/DRC checks", dest="check_lvsdrc"), - optparse.make_option("-q", "--quiet", action="store_false", dest="print_banner", - help="Don\'t display banner"), optparse.make_option("-v", "--verbose", action="count", dest="debug_level", help="Increase the verbosity level"), optparse.make_option("-t", "--tech", dest="tech_name", @@ -50,14 +39,16 @@ def parse_args(): optparse.make_option("-r", "--remove_netlist_trimming", action="store_false", dest="trim_netlist", help="Disable removal of noncritical memory cells during characterization"), optparse.make_option("-c", "--characterize", action="store_false", dest="analytical_delay", - help="Perform characterization to calculate delays (default is analytical models)") + help="Perform characterization to calculate delays (default is analytical models)"), + optparse.make_option("-d", "--dontpurge", action="store_false", dest="purge_temp", + help="Don't purge the contents of the temp directory after a successful run") # -h --help is implicit. } parser = optparse.OptionParser(option_list=option_list, description="Compile and/or characterize an SRAM.", usage=USAGE, - version="OpenRAM v" + VERSION) + version="OpenRAM") (options, args) = parser.parse_args(values=OPTS) # If we don't specify a tech, assume freepdk45. @@ -67,17 +58,17 @@ def parse_args(): # Alias SCMOS to AMI 0.5um if OPTS.tech_name == "scmos": OPTS.tech_name = "scn3me_subm" - + return (options, args) def print_banner(): """ Conditionally print the banner to stdout """ global OPTS - if not OPTS.print_banner: + if OPTS.is_unit_test: return print("|==============================================================================|") - name = "OpenRAM Compiler v"+VERSION + name = "OpenRAM Compiler" print("|=========" + name.center(60) + "=========|") print("|=========" + " ".center(60) + "=========|") print("|=========" + "VLSI Design and Automation Lab".center(60) + "=========|") @@ -86,22 +77,41 @@ def print_banner(): print("|=========" + "VLSI Computer Architecture Research Group".center(60) + "=========|") print("|=========" + "Oklahoma State University ECE Department".center(60) + "=========|") print("|=========" + " ".center(60) + "=========|") - print("|=========" + OPTS.openram_temp.center(60) + "=========|") + user_info = "Usage help: openram-user-group@ucsc.edu" + print("|=========" + user_info.center(60) + "=========|") + dev_info = "Development help: openram-dev-group@ucsc.edu" + print("|=========" + dev_info.center(60) + "=========|") + temp_info = "Temp dir: {}".format(OPTS.openram_temp) + print("|=========" + temp_info.center(60) + "=========|") print("|==============================================================================|") -def init_openram(config_file): +def check_versions(): + """ Run some checks of required software versions. """ + + # check that we are not using version 3 and at least 2.7 + major_python_version = sys.version_info.major + minor_python_version = sys.version_info.minor + if not (major_python_version == 2 and minor_python_version >= 7): + debug.error("Python 2.7 is required.",-1) + + # FIXME: Check versions of other tools here?? + # or, this could be done in each module (e.g. verify, characterizer, etc.) + +def init_openram(config_file, is_unit_test=True): """Initialize the technology, paths, simulators, etc.""" + check_versions() debug.info(1,"Initializing OpenRAM...") setup_paths() - read_config(config_file) + read_config(config_file, is_unit_test) import_tech() + def get_tool(tool_type, preferences): """ Find which tool we have from a list of preferences and return the @@ -121,7 +131,7 @@ def get_tool(tool_type, preferences): -def read_config(config_file): +def read_config(config_file, is_unit_test=True): """ Read the configuration file that defines a few parameters. The config file is just a Python file that defines some config @@ -159,6 +169,16 @@ def read_config(config_file): OPTS.output_path += "/" debug.info(1, "Output saved in " + OPTS.output_path) + OPTS.is_unit_test=is_unit_test + + # If config didn't set output name, make a reasonable default. + if (OPTS.output_name == ""): + OPTS.output_name = "sram_{0}rw_{1}b_{2}w_{3}bank_{4}".format(OPTS.rw_ports, + OPTS.word_size, + OPTS.num_words, + OPTS.num_banks, + OPTS.tech_name) + # Don't delete the output dir, it may have other files! # make the directory if it doesn't exist try: @@ -174,17 +194,17 @@ def read_config(config_file): def end_openram(): """ Clean up openram for a proper exit """ cleanup_paths() + - # Reset the static duplicate name checker for unit tests. - # This is needed for running unit tests. - import design - design.design.name_map=[] def cleanup_paths(): """ We should clean up the temp directory after execution. """ + if not OPTS.purge_temp: + debug.info(0,"Preserving temp directory: {}".format(OPTS.openram_temp)) + return if os.path.exists(OPTS.openram_temp): shutil.rmtree(OPTS.openram_temp, ignore_errors=True) @@ -199,16 +219,14 @@ def setup_paths(): except: debug.error("$OPENRAM_HOME is not properly defined.",1) debug.check(os.path.isdir(OPENRAM_HOME),"$OPENRAM_HOME does not exist: {0}".format(OPENRAM_HOME)) - - debug.check(os.path.isdir(OPENRAM_HOME+"/gdsMill"), - "$OPENRAM_HOME/gdsMill does not exist: {0}".format(OPENRAM_HOME+"/gdsMill")) - sys.path.append("{0}/gdsMill".format(OPENRAM_HOME)) - debug.check(os.path.isdir(OPENRAM_HOME+"/tests"), - "$OPENRAM_HOME/tests does not exist: {0}".format(OPENRAM_HOME+"/tests")) - sys.path.append("{0}/tests".format(OPENRAM_HOME)) - debug.check(os.path.isdir(OPENRAM_HOME+"/router"), - "$OPENRAM_HOME/router does not exist: {0}".format(OPENRAM_HOME+"/router")) - sys.path.append("{0}/router".format(OPENRAM_HOME)) + + # Add all of the subdirs to the python path + # These subdirs are modules and don't need to be added: characterizer, verify + for subdir in ["gdsMill", "tests", "router", "modules", "base", "pgates"]: + full_path = "{0}/{1}".format(OPENRAM_HOME,subdir) + debug.check(os.path.isdir(full_path), + "$OPENRAM_HOME/{0} does not exist: {1}".format(subdir,full_path)) + sys.path.append("{0}".format(full_path)) if not OPTS.openram_temp.endswith('/'): OPTS.openram_temp += "/" @@ -246,9 +264,8 @@ def import_tech(): # Set the tech to the config file we read in instead of the command line value. OPTS.tech_name = OPTS.tech_name - - - # environment variable should point to the technology dir + + # environment variable should point to the technology dir try: OPENRAM_TECH = os.path.abspath(os.environ.get("OPENRAM_TECH")) except: @@ -272,3 +289,43 @@ def import_tech(): debug.error("Nonexistent technology_setup_file: {0}.py".format(filename)) sys.exit(1) + import tech + # Set some default options now based on the technology... + if (OPTS.process_corners == ""): + OPTS.process_corners = tech.spice["fet_models"].keys() + if (OPTS.supply_voltages == ""): + OPTS.supply_voltages = tech.spice["supply_voltages"] + if (OPTS.temperatures == ""): + OPTS.temperatures = tech.spice["temperatures"] + + +def print_time(name, now_time, last_time=None): + """ Print a statement about the time delta. """ + if last_time: + time = round((now_time-last_time).total_seconds(),1) + else: + time = now_time + print("** {0}: {1} seconds".format(name,time)) + + +def report_status(): + """ Check for valid arguments and report the info about the SRAM being generated """ + # Check if all arguments are integers for bits, size, banks + if type(OPTS.word_size)!=int: + debug.error("{0} is not an integer in config file.".format(OPTS.word_size)) + if type(OPTS.num_words)!=int: + debug.error("{0} is not an integer in config file.".format(OPTS.sram_size)) + if type(OPTS.num_banks)!=int: + debug.error("{0} is not an integer in config file.".format(OPTS.num_banks)) + + if not OPTS.tech_name: + debug.error("Tech name must be specified in config file.") + + print("Output files are " + OPTS.output_name + ".(sp|gds|v|lib|lef)") + print("Technology: {0}".format(OPTS.tech_name)) + print("Word size: {0}\nWords: {1}\nBanks: {2}".format(OPTS.word_size, + OPTS.num_words, + OPTS.num_banks)) + if not OPTS.check_lvsdrc: + print("DRC/LVS/PEX checking is disabled.") + diff --git a/compiler/bank.py b/compiler/modules/bank.py similarity index 99% rename from compiler/bank.py rename to compiler/modules/bank.py index ba59a8e9..0d38e61e 100644 --- a/compiler/bank.py +++ b/compiler/modules/bank.py @@ -99,8 +99,10 @@ class bank(design.design): self.add_precharge_array() if self.col_addr_size > 0: + # The m2 width is because the 6T cell may have vias on the boundary edge for + # overlapping when making the array + self.column_mux_height = self.column_mux_array.height + 0.5*self.m2_width self.add_column_mux_array() - self.column_mux_height = self.column_mux_array.height else: self.column_mux_height = 0 if self.col_addr_size > 1: # size 1 is from addr FF @@ -249,7 +251,7 @@ class bank(design.design): def add_column_mux_array(self): """ Adding Column Mux when words_per_row > 1 . """ - y_offset = self.column_mux_array.height + y_offset = self.column_mux_height self.col_mux_array_inst=self.add_inst(name="column_mux_array", mod=self.column_mux_array, offset=vector(0,y_offset).scale(-1,-1)) @@ -434,7 +436,8 @@ class bank(design.design): # Place the col decoder just to the left of the control bus - x_off = self.m2_pitch + self.overall_central_bus_width + self.col_decoder.width + gap = max(drc["pwell_to_nwell"], 2*self.m2_pitch) + x_off = gap + self.overall_central_bus_width + self.col_decoder.width # Place the col decoder below the the address flops which are below the row decoder (lave some space for wells) vertical_gap = max(drc["pwell_to_nwell"], 2*self.m2_pitch) y_off = self.decoder.predecoder_height + self.msf_address.width + self.col_decoder.height + 2*vertical_gap diff --git a/compiler/bitcell.py b/compiler/modules/bitcell.py similarity index 100% rename from compiler/bitcell.py rename to compiler/modules/bitcell.py diff --git a/compiler/bitcell_array.py b/compiler/modules/bitcell_array.py similarity index 100% rename from compiler/bitcell_array.py rename to compiler/modules/bitcell_array.py diff --git a/compiler/control_logic.py b/compiler/modules/control_logic.py similarity index 96% rename from compiler/control_logic.py rename to compiler/modules/control_logic.py index eceeb29a..a3de587c 100644 --- a/compiler/control_logic.py +++ b/compiler/modules/control_logic.py @@ -68,7 +68,10 @@ class control_logic(design.design): c = reload(__import__(OPTS.replica_bitline)) replica_bitline = getattr(c, OPTS.replica_bitline) - self.replica_bitline = replica_bitline(rows=int(math.ceil(self.num_rows / 10.0))) + # FIXME: These should be tuned according to the size! + FO4_stages = 8 + bitcell_loads = int(math.ceil(self.num_rows / 10.0)) + self.replica_bitline = replica_bitline(FO4_stages, bitcell_loads) self.add_mod(self.replica_bitline) @@ -77,8 +80,6 @@ class control_logic(design.design): # These aren't for instantiating, but we use them to get the dimensions self.poly_contact_offset = vector(0.5*contact.poly.width,0.5*contact.poly.height) - # For different layer width vias - self.m1m2_offset_fix = vector(0,0.5*(drc["minwidth_metal2"]-drc["minwidth_metal1"])) # M1/M2 routing pitch is based on contacted pitch self.m1_pitch = max(contact.m1m2.width,contact.m1m2.height) + max(drc["metal1_to_metal1"],drc["metal2_to_metal2"]) self.m2_pitch = max(contact.m2m3.width,contact.m2m3.height) + max(drc["metal2_to_metal2"],drc["metal3_to_metal3"]) @@ -87,10 +88,6 @@ class control_logic(design.design): # Some cells may have pwell/nwell spacing problems too when the wells are different heights. self.cell_gap = max(self.m2_pitch,drc["pwell_to_nwell"]) - # Amount to shift a 90 degree rotated via from center-line path routing to it's offset - self.m1m2_via_offset = vector(contact.m1m2.first_layer_height,-0.5*drc["minwidth_metal2"]) - self.m2m3_via_offset = vector(contact.m2m3.first_layer_height,-0.5*drc["minwidth_metal3"]) - # First RAIL Parameters: gnd, oe, oebar, cs, we, clk_buf, clk_bar self.rail_1_start_x = 0 self.num_rails_1 = 8 @@ -326,6 +323,7 @@ class control_logic(design.design): x_off += self.inv1.width # BUFFER INVERTERS FOR W_EN + # FIXME: Can we remove these two invs and size the previous one? self.pre_w_en_bar_offset = vector(x_off, y_off) self.pre_w_en_bar=self.add_inst(name="inv_pre_w_en_bar", mod=self.inv1, @@ -512,11 +510,25 @@ class control_logic(design.design): offset=clk_buf_rail_position, rotate=90) - # clk_bar - self.connect_rail_from_left_m2m3(self.clk_bar,"Z","clk_bar") + # clk_bar, routes over the clock buffer vdd rail + clk_pin = self.clk_bar.get_pin("Z") + vdd_pin = self.clk_bar.get_pin("vdd") + # move the output pin up to metal2 self.add_via_center(layers=("metal1","via1","metal2"), - offset=self.clk_bar.get_pin("Z").rc(), + offset=clk_pin.rc(), rotate=90) + # route to a position over the supply rail + in_pos = vector(clk_pin.rx(), vdd_pin.cy()) + self.add_path("metal2",[clk_pin.rc(), in_pos]) + # connect that position to the control bus + rail_pos = vector(self.rail_1_x_offsets["clk_bar"], in_pos.y) + self.add_wire(("metal3","via2","metal2"),[in_pos, rail_pos]) + self.add_via_center(layers=("metal2","via2","metal3"), + offset=in_pos, + rotate=90) + self.add_via_center(layers=("metal2","via2","metal3"), + offset=rail_pos, + rotate=90) # clk_buf to msf control flops msf_clk_pos = self.msf_inst.get_pin("clk").bc() diff --git a/compiler/delay_chain.py b/compiler/modules/delay_chain.py similarity index 98% rename from compiler/delay_chain.py rename to compiler/modules/delay_chain.py index 5a97f711..b05da7ee 100644 --- a/compiler/delay_chain.py +++ b/compiler/modules/delay_chain.py @@ -8,7 +8,8 @@ from globals import OPTS class delay_chain(design.design): """ - Generate a logic effort based delay chain. + Generate a delay chain with the given number of stages and fanout. + This automatically adds an extra inverter with no load on the input. Input is a list contains the electrical effort of each stage. """ diff --git a/compiler/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py similarity index 100% rename from compiler/hierarchical_decoder.py rename to compiler/modules/hierarchical_decoder.py diff --git a/compiler/hierarchical_predecode.py b/compiler/modules/hierarchical_predecode.py similarity index 99% rename from compiler/hierarchical_predecode.py rename to compiler/modules/hierarchical_predecode.py index b3f3ddc1..7e336405 100644 --- a/compiler/hierarchical_predecode.py +++ b/compiler/modules/hierarchical_predecode.py @@ -250,9 +250,9 @@ class hierarchical_predecode(design.design): index_lst= nand_input_line_combination[k] if self.number_of_inputs == 2: - gate_lst = ["B","A"] + gate_lst = ["A","B"] else: - gate_lst = ["C","B","A"] + gate_lst = ["A","B","C"] # this will connect pins A,B or A,B,C for rail_pin,gate_pin in zip(index_lst,gate_lst): diff --git a/compiler/hierarchical_predecode2x4.py b/compiler/modules/hierarchical_predecode2x4.py similarity index 94% rename from compiler/hierarchical_predecode2x4.py rename to compiler/modules/hierarchical_predecode2x4.py index 905342c8..bedc568d 100644 --- a/compiler/hierarchical_predecode2x4.py +++ b/compiler/modules/hierarchical_predecode2x4.py @@ -27,10 +27,10 @@ class hierarchical_predecode2x4(hierarchical_predecode): self.create_rails() self.add_input_inverters() self.add_output_inverters() - connections =[["in[0]", "in[1]", "Z[3]", "vdd", "gnd"], - ["inbar[0]", "in[1]", "Z[2]", "vdd", "gnd"], + connections =[["inbar[0]", "inbar[1]", "Z[0]", "vdd", "gnd"], ["in[0]", "inbar[1]", "Z[1]", "vdd", "gnd"], - ["inbar[0]", "inbar[1]", "Z[0]", "vdd", "gnd"]] + ["inbar[0]", "in[1]", "Z[2]", "vdd", "gnd"], + ["in[0]", "in[1]", "Z[3]", "vdd", "gnd"]] self.add_nand(connections) self.route() diff --git a/compiler/hierarchical_predecode3x8.py b/compiler/modules/hierarchical_predecode3x8.py similarity index 100% rename from compiler/hierarchical_predecode3x8.py rename to compiler/modules/hierarchical_predecode3x8.py diff --git a/compiler/ms_flop.py b/compiler/modules/ms_flop.py similarity index 100% rename from compiler/ms_flop.py rename to compiler/modules/ms_flop.py diff --git a/compiler/ms_flop_array.py b/compiler/modules/ms_flop_array.py similarity index 100% rename from compiler/ms_flop_array.py rename to compiler/modules/ms_flop_array.py diff --git a/compiler/precharge.py b/compiler/modules/precharge.py similarity index 93% rename from compiler/precharge.py rename to compiler/modules/precharge.py index d2a64678..26e3b5f1 100644 --- a/compiler/precharge.py +++ b/compiler/modules/precharge.py @@ -29,13 +29,13 @@ class precharge(pgate.pgate): self.DRC_LVS() def add_pins(self): - self.add_pin_list(["bl", "br", "clk", "vdd"]) + self.add_pin_list(["bl", "br", "en", "vdd"]) def create_layout(self): self.create_ptx() self.add_ptx() self.connect_poly() - self.add_pclk() + self.add_en() self.add_nwell_and_contact() self.add_vdd_rail() self.add_bitlines() @@ -74,7 +74,7 @@ class precharge(pgate.pgate): self.lower_pmos_inst=self.add_inst(name="lower_pmos", mod=self.pmos, offset=self.lower_pmos_position) - self.connect_inst(["bl", "clk", "BR", "vdd"]) + self.connect_inst(["bl", "en", "BR", "vdd"]) # adds the upper pmos(s) to layout ydiff = self.pmos.height + 2*self.m1_space + contact.poly.width @@ -82,13 +82,13 @@ class precharge(pgate.pgate): self.upper_pmos1_inst=self.add_inst(name="upper_pmos1", mod=self.pmos, offset=self.upper_pmos1_pos) - self.connect_inst(["bl", "clk", "vdd", "vdd"]) + self.connect_inst(["bl", "en", "vdd", "vdd"]) upper_pmos2_pos = self.upper_pmos1_pos + self.overlap_offset self.upper_pmos2_inst=self.add_inst(name="upper_pmos2", mod=self.pmos, offset=upper_pmos2_pos) - self.connect_inst(["br", "clk", "vdd", "vdd"]) + self.connect_inst(["br", "en", "vdd", "vdd"]) def connect_poly(self): """Connects the upper and lower pmos together""" @@ -109,16 +109,16 @@ class precharge(pgate.pgate): width=xlength, height=self.poly_width) - def add_pclk(self): - """Adds the pclk input rail, pclk contact/vias, and connects to the pmos""" - # adds the pclk contact to connect the gates to the pclk rail on metal1 + def add_en(self): + """Adds the en input rail, en contact/vias, and connects to the pmos""" + # adds the en contact to connect the gates to the en rail on metal1 offset = self.lower_pmos_inst.get_pin("G").ul() + vector(0,0.5*self.poly_space) self.add_contact_center(layers=("poly", "contact", "metal1"), offset=offset, rotate=90) - # adds the pclk rail on metal1 - self.add_layout_pin_center_segment(text="clk", + # adds the en rail on metal1 + self.add_layout_pin_center_segment(text="en", layer="metal1", start=offset.scale(0,1), end=offset.scale(0,1)+vector(self.width,0)) diff --git a/compiler/precharge_array.py b/compiler/modules/precharge_array.py similarity index 97% rename from compiler/precharge_array.py rename to compiler/modules/precharge_array.py index 7c91f126..f72e64fb 100644 --- a/compiler/precharge_array.py +++ b/compiler/modules/precharge_array.py @@ -46,7 +46,7 @@ class precharge_array(design.design): self.add_layout_pin(text="en", layer="metal1", - offset=self.pc_cell.get_pin("clk").ll(), + offset=self.pc_cell.get_pin("en").ll(), width=self.width, height=drc["minwidth_metal1"]) diff --git a/compiler/replica_bitcell.py b/compiler/modules/replica_bitcell.py similarity index 100% rename from compiler/replica_bitcell.py rename to compiler/modules/replica_bitcell.py diff --git a/compiler/replica_bitline.py b/compiler/modules/replica_bitline.py similarity index 81% rename from compiler/replica_bitline.py rename to compiler/modules/replica_bitline.py index bed1ebb2..6be7dc77 100644 --- a/compiler/replica_bitline.py +++ b/compiler/modules/replica_bitline.py @@ -10,12 +10,12 @@ from globals import OPTS class replica_bitline(design.design): """ - Generate a module that simulate the delay of control logic - and bit line charging. - Used for memory timing control + Generate a module that simulates the delay of control logic + and bit line charging. Stages is the depth of the FO4 delay + line and rows is the height of the replica bit loads. """ - def __init__(self, rows, name="replica_bitline"): + def __init__(self, FO4_stages, bitcell_loads, name="replica_bitline"): design.design.__init__(self, name) g = reload(__import__(OPTS.delay_chain)) @@ -29,7 +29,8 @@ class replica_bitline(design.design): for pin in ["en", "out", "vdd", "gnd"]: self.add_pin(pin) - self.rows = rows + self.bitcell_loads = bitcell_loads + self.FO4_stages = FO4_stages self.create_modules() self.calculate_module_offsets() @@ -78,10 +79,11 @@ class replica_bitline(design.design): self.add_mod(self.bitcell) # This is the replica bitline load column that is the height of our array - self.rbl = bitcell_array(name="bitline_load", cols=1, rows=self.rows) + self.rbl = bitcell_array(name="bitline_load", cols=1, rows=self.bitcell_loads) self.add_mod(self.rbl) - - self.delay_chain = self.mod_delay_chain([1, 1, 1]) + + # FIXME: The FO and depth of this should be tuned + self.delay_chain = self.mod_delay_chain([4]*self.FO4_stages) self.add_mod(self.delay_chain) self.inv = pinv() @@ -123,7 +125,7 @@ class replica_bitline(design.design): self.rbl_inst=self.add_inst(name="load", mod=self.rbl, offset=self.rbl_offset) - self.connect_inst(["bl[0]", "br[0]"] + ["gnd"]*self.rows + ["vdd", "gnd"]) + self.connect_inst(["bl[0]", "br[0]"] + ["gnd"]*self.bitcell_loads + ["vdd", "gnd"]) @@ -239,56 +241,61 @@ class replica_bitline(design.design): def route_gnd(self): """ Route all signals connected to gnd """ - # Add a rail in M1 from bottom to two along delay chain - gnd_start = self.rbl_inv_inst.get_pin("gnd").ll() - self.offset_fix + gnd_start = self.rbl_inv_inst.get_pin("gnd").bc() + gnd_end = vector(gnd_start.x, self.rbl_inst.uy()+2*self.m2_pitch) - # It is the height of the entire RBL and bitcell - self.add_rect(layer="metal2", - offset=gnd_start, - width=self.m2_width, - height=self.rbl.height+self.bitcell.height+self.inv.width+self.m2_pitch) - self.add_layout_pin(text="gnd", - layer="metal1", - offset=gnd_start.scale(1,0), - width=self.m2_width, - height=2*self.inv.width) + # Add a rail in M1 from bottom of delay chain to two above the RBL + # This prevents DRC errors with vias for the WL + dc_top = self.dc_inst.ur() + self.add_segment_center(layer="metal1", + start=vector(gnd_start.x, dc_top.y), + end=gnd_end) + + # Add a rail in M2 from RBL inverter to two above the RBL + self.add_segment_center(layer="metal2", + start=gnd_start, + end=gnd_end) + + # Add pin from bottom to RBL inverter + self.add_layout_pin_center_segment(text="gnd", + layer="metal1", + start=gnd_start.scale(1,0), + end=gnd_start) # Connect the WL pins directly to gnd - for row in range(self.rows): + gnd_pin = self.get_pin("gnd").rc() + for row in range(self.bitcell_loads): wl = "wl[{}]".format(row) pin = self.rbl_inst.get_pin(wl) - offset = vector(gnd_start.x,pin.by()) - self.add_rect(layer="metal1", - offset=offset, - width=self.rbl_offset.x-gnd_start.x, - height=self.m1_width) - self.add_via(layers=("metal1", "via1", "metal2"), - offset=offset) + start = vector(gnd_pin.x,pin.cy()) + self.add_segment_center(layer="metal1", + start=start, + end=pin.lc()) + self.add_via_center(layers=("metal1", "via1", "metal2"), + offset=start) # Add via for the delay chain - offset = self.delay_chain_offset - vector(0.5*self.m1_width,0) - self.offset_fix - self.add_via(layers=("metal1", "via1", "metal2"), - offset=offset) + offset = self.dc_inst.get_pins("gnd")[0].bc() + vector(0.5*contact.m1m2.width,0.5*contact.m1m2.height) + self.add_via_center(layers=("metal1", "via1", "metal2"), + offset=offset) # Add via for the inverter - offset = self.rbl_inv_offset - vector(0.5*self.m1_width,contact.m1m2.height) - self.offset_fix - self.add_via(layers=("metal1", "via1", "metal2"), - offset=offset) + offset = self.rbl_inv_inst.get_pin("gnd").bc() - vector(0,0.5*contact.m1m2.height) + self.add_via_center(layers=("metal1", "via1", "metal2"), + offset=offset) - # Connect the bitcell gnd pin to the rail + # Connect the bitcell gnd pins to the rail gnd_pins = self.get_pins("gnd") - gnd_start = gnd_pins[0].uc() + gnd_start = gnd_pins[0].ul() rbl_gnd_pins = self.rbl_inst.get_pins("gnd") - # Find the left most rail on M2 - gnd_pin = None + # Add L shapes to each vertical gnd rail for pin in rbl_gnd_pins: - if gnd_pin == None or (pin.layer=="metal2" and pin.lx()0) + # grep any errors from the output output = open("{0}/output.log".format(out_path),"r").read() self.assertEqual(len(re.findall('ERROR',output)),0) diff --git a/compiler/tests/config_20_freepdk45.py b/compiler/tests/config_20_freepdk45.py index 4eb4f091..d7e1880e 100644 --- a/compiler/tests/config_20_freepdk45.py +++ b/compiler/tests/config_20_freepdk45.py @@ -3,5 +3,8 @@ num_words = 16 num_banks = 1 tech_name = "freepdk45" +process_corners = ["TT"] +supply_voltages = [1.0] +temperatures = [25] diff --git a/compiler/tests/config_20_scn3me_subm.py b/compiler/tests/config_20_scn3me_subm.py index 178eb91e..40addd69 100644 --- a/compiler/tests/config_20_scn3me_subm.py +++ b/compiler/tests/config_20_scn3me_subm.py @@ -3,4 +3,7 @@ num_words = 16 num_banks = 1 tech_name = "scn3me_subm" +process_corners = ["TT"] +supply_voltages = [5.0] +temperatures = [25] diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45.lef b/compiler/tests/golden/sram_2_16_1_freepdk45.lef index 88cd5035..b2d656fe 100644 --- a/compiler/tests/golden/sram_2_16_1_freepdk45.lef +++ b/compiler/tests/golden/sram_2_16_1_freepdk45.lef @@ -7,11 +7,11 @@ UNITS END UNITS SITE MacroSite CLASS Core ; - SIZE 175.0 by 135.0 ; + SIZE 21695.0 by 42337.5 ; END MacroSite MACRO sram_2_16_1_freepdk45 CLASS BLOCK ; - SIZE 175.0 BY 135.0 ; + SIZE 21695.0 BY 42337.5 ; SYMMETRY X Y R90 ; SITE MacroSite ; PIN DATA[0] @@ -606,14 +606,14 @@ MACRO sram_2_16_1_freepdk45 RECT 10785.0 10360.0 10420.0 10425.0 ; RECT 11060.0 11122.5 9125.0 11187.5 ; RECT 10785.0 12467.5 8850.0 12532.5 ; - RECT 9675.0 8722.5 8292.5 8787.5 ; - RECT 9400.0 8937.5 8550.0 9002.5 ; - RECT 9125.0 10562.5 8292.5 10627.5 ; - RECT 9400.0 10347.5 8550.0 10412.5 ; - RECT 9675.0 11412.5 8292.5 11477.5 ; - RECT 8850.0 11627.5 8550.0 11692.5 ; - RECT 9125.0 13252.5 8292.5 13317.5 ; - RECT 8850.0 13037.5 8550.0 13102.5 ; + RECT 9675.0 8937.5 8550.0 9002.5 ; + RECT 9400.0 8722.5 8292.5 8787.5 ; + RECT 9125.0 10347.5 8550.0 10412.5 ; + RECT 9400.0 10562.5 8292.5 10627.5 ; + RECT 9675.0 11627.5 8550.0 11692.5 ; + RECT 8850.0 11412.5 8292.5 11477.5 ; + RECT 9125.0 13037.5 8550.0 13102.5 ; + RECT 8850.0 13252.5 8292.5 13317.5 ; RECT 7845.0 8937.5 7780.0 9002.5 ; RECT 7845.0 8925.0 7780.0 8990.0 ; RECT 8062.5 8937.5 7812.5 9002.5 ; @@ -894,14 +894,14 @@ MACRO sram_2_16_1_freepdk45 RECT 9057.5 11122.5 9192.5 11187.5 ; RECT 10717.5 12467.5 10852.5 12532.5 ; RECT 8782.5 12467.5 8917.5 12532.5 ; - RECT 9607.5 8722.5 9742.5 8787.5 ; - RECT 9332.5 8937.5 9467.5 9002.5 ; - RECT 9057.5 10562.5 9192.5 10627.5 ; - RECT 9332.5 10347.5 9467.5 10412.5 ; - RECT 9607.5 11412.5 9742.5 11477.5 ; - RECT 8782.5 11627.5 8917.5 11692.5 ; - RECT 9057.5 13252.5 9192.5 13317.5 ; - RECT 8782.5 13037.5 8917.5 13102.5 ; + RECT 9607.5 8937.5 9742.5 9002.5 ; + RECT 9332.5 8722.5 9467.5 8787.5 ; + RECT 9057.5 10347.5 9192.5 10412.5 ; + RECT 9332.5 10562.5 9467.5 10627.5 ; + RECT 9607.5 11627.5 9742.5 11692.5 ; + RECT 8782.5 11412.5 8917.5 11477.5 ; + RECT 9057.5 13037.5 9192.5 13102.5 ; + RECT 8782.5 13252.5 8917.5 13317.5 ; RECT 7335.0 8925.0 7130.0 8990.0 ; RECT 7335.0 10360.0 7130.0 10425.0 ; RECT 7335.0 11615.0 7130.0 11680.0 ; @@ -925,14 +925,14 @@ MACRO sram_2_16_1_freepdk45 RECT 10785.0 15740.0 10420.0 15805.0 ; RECT 11060.0 16502.5 9125.0 16567.5 ; RECT 10785.0 17847.5 8850.0 17912.5 ; - RECT 9675.0 14102.5 8292.5 14167.5 ; - RECT 9400.0 14317.5 8550.0 14382.5 ; - RECT 9125.0 15942.5 8292.5 16007.5 ; - RECT 9400.0 15727.5 8550.0 15792.5 ; - RECT 9675.0 16792.5 8292.5 16857.5 ; - RECT 8850.0 17007.5 8550.0 17072.5 ; - RECT 9125.0 18632.5 8292.5 18697.5 ; - RECT 8850.0 18417.5 8550.0 18482.5 ; + RECT 9675.0 14317.5 8550.0 14382.5 ; + RECT 9400.0 14102.5 8292.5 14167.5 ; + RECT 9125.0 15727.5 8550.0 15792.5 ; + RECT 9400.0 15942.5 8292.5 16007.5 ; + RECT 9675.0 17007.5 8550.0 17072.5 ; + RECT 8850.0 16792.5 8292.5 16857.5 ; + RECT 9125.0 18417.5 8550.0 18482.5 ; + RECT 8850.0 18632.5 8292.5 18697.5 ; RECT 7845.0 14317.5 7780.0 14382.5 ; RECT 7845.0 14305.0 7780.0 14370.0 ; RECT 8062.5 14317.5 7812.5 14382.5 ; @@ -1213,14 +1213,14 @@ MACRO sram_2_16_1_freepdk45 RECT 9057.5 16502.5 9192.5 16567.5 ; RECT 10717.5 17847.5 10852.5 17912.5 ; RECT 8782.5 17847.5 8917.5 17912.5 ; - RECT 9607.5 14102.5 9742.5 14167.5 ; - RECT 9332.5 14317.5 9467.5 14382.5 ; - RECT 9057.5 15942.5 9192.5 16007.5 ; - RECT 9332.5 15727.5 9467.5 15792.5 ; - RECT 9607.5 16792.5 9742.5 16857.5 ; - RECT 8782.5 17007.5 8917.5 17072.5 ; - RECT 9057.5 18632.5 9192.5 18697.5 ; - RECT 8782.5 18417.5 8917.5 18482.5 ; + RECT 9607.5 14317.5 9742.5 14382.5 ; + RECT 9332.5 14102.5 9467.5 14167.5 ; + RECT 9057.5 15727.5 9192.5 15792.5 ; + RECT 9332.5 15942.5 9467.5 16007.5 ; + RECT 9607.5 17007.5 9742.5 17072.5 ; + RECT 8782.5 16792.5 8917.5 16857.5 ; + RECT 9057.5 18417.5 9192.5 18482.5 ; + RECT 8782.5 18632.5 8917.5 18697.5 ; RECT 7335.0 14305.0 7130.0 14370.0 ; RECT 7335.0 15740.0 7130.0 15805.0 ; RECT 7335.0 16995.0 7130.0 17060.0 ; @@ -4165,9 +4165,11 @@ MACRO sram_2_16_1_freepdk45 RECT 750.0 30905.0 685.0 30970.0 ; RECT 32.5 30615.0 -32.5 31175.0 ; RECT 1377.5 30615.0 1312.5 31175.0 ; - RECT 1380.0 33907.5 935.0 33972.5 ; - RECT 1380.0 36317.5 935.0 36382.5 ; - RECT 1345.0 36817.5 935.0 36882.5 ; + RECT 1377.5 39337.5 1312.5 36955.0 ; + RECT 1312.5 33907.5 1025.0 33972.5 ; + RECT 1312.5 36317.5 1025.0 36382.5 ; + RECT 1377.5 31862.5 935.0 31927.5 ; + RECT 935.0 31862.5 230.0 31927.5 ; RECT 20.0 35112.5 935.0 35177.5 ; RECT 20.0 32422.5 935.0 32487.5 ; RECT 2005.0 33435.0 1940.0 34135.0 ; @@ -4208,11 +4210,11 @@ MACRO sram_2_16_1_freepdk45 RECT 2330.0 33497.5 2465.0 33562.5 ; RECT 2330.0 33497.5 2465.0 33562.5 ; RECT 2330.0 33307.5 2465.0 33372.5 ; - RECT 1312.5 35352.5 1377.5 35417.5 ; - RECT 4002.5 35352.5 4067.5 35417.5 ; - RECT 1312.5 35255.0 1377.5 35385.0 ; - RECT 1345.0 35352.5 4035.0 35417.5 ; - RECT 4002.5 35255.0 4067.5 35385.0 ; + RECT 1312.5 39272.5 1377.5 39337.5 ; + RECT 4002.5 39272.5 4067.5 39337.5 ; + RECT 1312.5 39175.0 1377.5 39305.0 ; + RECT 1345.0 39272.5 4035.0 39337.5 ; + RECT 4002.5 39175.0 4067.5 39305.0 ; RECT 2875.0 34562.5 2690.0 34627.5 ; RECT 4035.0 34562.5 3850.0 34627.5 ; RECT 3917.5 34202.5 4067.5 34267.5 ; @@ -4254,6 +4256,279 @@ MACRO sram_2_16_1_freepdk45 RECT 2722.5 34695.0 2657.5 35255.0 ; RECT 4067.5 34695.0 4002.5 35255.0 ; RECT 3340.0 34820.0 3475.0 34885.0 ; + RECT 2875.0 35682.5 2690.0 35747.5 ; + RECT 4035.0 35682.5 3850.0 35747.5 ; + RECT 3917.5 35322.5 4067.5 35387.5 ; + RECT 3032.5 35322.5 2657.5 35387.5 ; + RECT 3917.5 35512.5 3032.5 35577.5 ; + RECT 3032.5 35322.5 2897.5 35387.5 ; + RECT 3032.5 35512.5 2897.5 35577.5 ; + RECT 3032.5 35512.5 2897.5 35577.5 ; + RECT 3032.5 35322.5 2897.5 35387.5 ; + RECT 3917.5 35322.5 3782.5 35387.5 ; + RECT 3917.5 35512.5 3782.5 35577.5 ; + RECT 3917.5 35512.5 3782.5 35577.5 ; + RECT 3917.5 35322.5 3782.5 35387.5 ; + RECT 2942.5 35682.5 2807.5 35747.5 ; + RECT 3917.5 35682.5 3782.5 35747.5 ; + RECT 3475.0 35380.0 3340.0 35445.0 ; + RECT 3475.0 35380.0 3340.0 35445.0 ; + RECT 3440.0 35545.0 3375.0 35610.0 ; + RECT 2722.5 35255.0 2657.5 35815.0 ; + RECT 4067.5 35255.0 4002.5 35815.0 ; + RECT 3340.0 35380.0 3475.0 35445.0 ; + RECT 2875.0 36242.5 2690.0 36307.5 ; + RECT 4035.0 36242.5 3850.0 36307.5 ; + RECT 3917.5 35882.5 4067.5 35947.5 ; + RECT 3032.5 35882.5 2657.5 35947.5 ; + RECT 3917.5 36072.5 3032.5 36137.5 ; + RECT 3032.5 35882.5 2897.5 35947.5 ; + RECT 3032.5 36072.5 2897.5 36137.5 ; + RECT 3032.5 36072.5 2897.5 36137.5 ; + RECT 3032.5 35882.5 2897.5 35947.5 ; + RECT 3917.5 35882.5 3782.5 35947.5 ; + RECT 3917.5 36072.5 3782.5 36137.5 ; + RECT 3917.5 36072.5 3782.5 36137.5 ; + RECT 3917.5 35882.5 3782.5 35947.5 ; + RECT 2942.5 36242.5 2807.5 36307.5 ; + RECT 3917.5 36242.5 3782.5 36307.5 ; + RECT 3475.0 35940.0 3340.0 36005.0 ; + RECT 3475.0 35940.0 3340.0 36005.0 ; + RECT 3440.0 36105.0 3375.0 36170.0 ; + RECT 2722.5 35815.0 2657.5 36375.0 ; + RECT 4067.5 35815.0 4002.5 36375.0 ; + RECT 3340.0 35940.0 3475.0 36005.0 ; + RECT 2875.0 36802.5 2690.0 36867.5 ; + RECT 4035.0 36802.5 3850.0 36867.5 ; + RECT 3917.5 36442.5 4067.5 36507.5 ; + RECT 3032.5 36442.5 2657.5 36507.5 ; + RECT 3917.5 36632.5 3032.5 36697.5 ; + RECT 3032.5 36442.5 2897.5 36507.5 ; + RECT 3032.5 36632.5 2897.5 36697.5 ; + RECT 3032.5 36632.5 2897.5 36697.5 ; + RECT 3032.5 36442.5 2897.5 36507.5 ; + RECT 3917.5 36442.5 3782.5 36507.5 ; + RECT 3917.5 36632.5 3782.5 36697.5 ; + RECT 3917.5 36632.5 3782.5 36697.5 ; + RECT 3917.5 36442.5 3782.5 36507.5 ; + RECT 2942.5 36802.5 2807.5 36867.5 ; + RECT 3917.5 36802.5 3782.5 36867.5 ; + RECT 3475.0 36500.0 3340.0 36565.0 ; + RECT 3475.0 36500.0 3340.0 36565.0 ; + RECT 3440.0 36665.0 3375.0 36730.0 ; + RECT 2722.5 36375.0 2657.5 36935.0 ; + RECT 4067.5 36375.0 4002.5 36935.0 ; + RECT 3340.0 36500.0 3475.0 36565.0 ; + RECT 2875.0 37362.5 2690.0 37427.5 ; + RECT 4035.0 37362.5 3850.0 37427.5 ; + RECT 3917.5 37002.5 4067.5 37067.5 ; + RECT 3032.5 37002.5 2657.5 37067.5 ; + RECT 3917.5 37192.5 3032.5 37257.5 ; + RECT 3032.5 37002.5 2897.5 37067.5 ; + RECT 3032.5 37192.5 2897.5 37257.5 ; + RECT 3032.5 37192.5 2897.5 37257.5 ; + RECT 3032.5 37002.5 2897.5 37067.5 ; + RECT 3917.5 37002.5 3782.5 37067.5 ; + RECT 3917.5 37192.5 3782.5 37257.5 ; + RECT 3917.5 37192.5 3782.5 37257.5 ; + RECT 3917.5 37002.5 3782.5 37067.5 ; + RECT 2942.5 37362.5 2807.5 37427.5 ; + RECT 3917.5 37362.5 3782.5 37427.5 ; + RECT 3475.0 37060.0 3340.0 37125.0 ; + RECT 3475.0 37060.0 3340.0 37125.0 ; + RECT 3440.0 37225.0 3375.0 37290.0 ; + RECT 2722.5 36935.0 2657.5 37495.0 ; + RECT 4067.5 36935.0 4002.5 37495.0 ; + RECT 3340.0 37060.0 3475.0 37125.0 ; + RECT 2875.0 37922.5 2690.0 37987.5 ; + RECT 4035.0 37922.5 3850.0 37987.5 ; + RECT 3917.5 37562.5 4067.5 37627.5 ; + RECT 3032.5 37562.5 2657.5 37627.5 ; + RECT 3917.5 37752.5 3032.5 37817.5 ; + RECT 3032.5 37562.5 2897.5 37627.5 ; + RECT 3032.5 37752.5 2897.5 37817.5 ; + RECT 3032.5 37752.5 2897.5 37817.5 ; + RECT 3032.5 37562.5 2897.5 37627.5 ; + RECT 3917.5 37562.5 3782.5 37627.5 ; + RECT 3917.5 37752.5 3782.5 37817.5 ; + RECT 3917.5 37752.5 3782.5 37817.5 ; + RECT 3917.5 37562.5 3782.5 37627.5 ; + RECT 2942.5 37922.5 2807.5 37987.5 ; + RECT 3917.5 37922.5 3782.5 37987.5 ; + RECT 3475.0 37620.0 3340.0 37685.0 ; + RECT 3475.0 37620.0 3340.0 37685.0 ; + RECT 3440.0 37785.0 3375.0 37850.0 ; + RECT 2722.5 37495.0 2657.5 38055.0 ; + RECT 4067.5 37495.0 4002.5 38055.0 ; + RECT 3340.0 37620.0 3475.0 37685.0 ; + RECT 2875.0 38482.5 2690.0 38547.5 ; + RECT 4035.0 38482.5 3850.0 38547.5 ; + RECT 3917.5 38122.5 4067.5 38187.5 ; + RECT 3032.5 38122.5 2657.5 38187.5 ; + RECT 3917.5 38312.5 3032.5 38377.5 ; + RECT 3032.5 38122.5 2897.5 38187.5 ; + RECT 3032.5 38312.5 2897.5 38377.5 ; + RECT 3032.5 38312.5 2897.5 38377.5 ; + RECT 3032.5 38122.5 2897.5 38187.5 ; + RECT 3917.5 38122.5 3782.5 38187.5 ; + RECT 3917.5 38312.5 3782.5 38377.5 ; + RECT 3917.5 38312.5 3782.5 38377.5 ; + RECT 3917.5 38122.5 3782.5 38187.5 ; + RECT 2942.5 38482.5 2807.5 38547.5 ; + RECT 3917.5 38482.5 3782.5 38547.5 ; + RECT 3475.0 38180.0 3340.0 38245.0 ; + RECT 3475.0 38180.0 3340.0 38245.0 ; + RECT 3440.0 38345.0 3375.0 38410.0 ; + RECT 2722.5 38055.0 2657.5 38615.0 ; + RECT 4067.5 38055.0 4002.5 38615.0 ; + RECT 3340.0 38180.0 3475.0 38245.0 ; + RECT 2875.0 39042.5 2690.0 39107.5 ; + RECT 4035.0 39042.5 3850.0 39107.5 ; + RECT 3917.5 38682.5 4067.5 38747.5 ; + RECT 3032.5 38682.5 2657.5 38747.5 ; + RECT 3917.5 38872.5 3032.5 38937.5 ; + RECT 3032.5 38682.5 2897.5 38747.5 ; + RECT 3032.5 38872.5 2897.5 38937.5 ; + RECT 3032.5 38872.5 2897.5 38937.5 ; + RECT 3032.5 38682.5 2897.5 38747.5 ; + RECT 3917.5 38682.5 3782.5 38747.5 ; + RECT 3917.5 38872.5 3782.5 38937.5 ; + RECT 3917.5 38872.5 3782.5 38937.5 ; + RECT 3917.5 38682.5 3782.5 38747.5 ; + RECT 2942.5 39042.5 2807.5 39107.5 ; + RECT 3917.5 39042.5 3782.5 39107.5 ; + RECT 3475.0 38740.0 3340.0 38805.0 ; + RECT 3475.0 38740.0 3340.0 38805.0 ; + RECT 3440.0 38905.0 3375.0 38970.0 ; + RECT 2722.5 38615.0 2657.5 39175.0 ; + RECT 4067.5 38615.0 4002.5 39175.0 ; + RECT 3340.0 38740.0 3475.0 38805.0 ; + RECT 2505.0 38187.5 2690.0 38122.5 ; + RECT 1345.0 38187.5 1530.0 38122.5 ; + RECT 1462.5 38547.5 1312.5 38482.5 ; + RECT 2347.5 38547.5 2722.5 38482.5 ; + RECT 1462.5 38357.5 2347.5 38292.5 ; + RECT 2347.5 38547.5 2482.5 38482.5 ; + RECT 2347.5 38357.5 2482.5 38292.5 ; + RECT 2347.5 38357.5 2482.5 38292.5 ; + RECT 2347.5 38547.5 2482.5 38482.5 ; + RECT 1462.5 38547.5 1597.5 38482.5 ; + RECT 1462.5 38357.5 1597.5 38292.5 ; + RECT 1462.5 38357.5 1597.5 38292.5 ; + RECT 1462.5 38547.5 1597.5 38482.5 ; + RECT 2437.5 38187.5 2572.5 38122.5 ; + RECT 1462.5 38187.5 1597.5 38122.5 ; + RECT 1905.0 38490.0 2040.0 38425.0 ; + RECT 1905.0 38490.0 2040.0 38425.0 ; + RECT 1940.0 38325.0 2005.0 38260.0 ; + RECT 2657.5 38615.0 2722.5 38055.0 ; + RECT 1312.5 38615.0 1377.5 38055.0 ; + RECT 1905.0 38425.0 2040.0 38490.0 ; + RECT 2505.0 37627.5 2690.0 37562.5 ; + RECT 1345.0 37627.5 1530.0 37562.5 ; + RECT 1462.5 37987.5 1312.5 37922.5 ; + RECT 2347.5 37987.5 2722.5 37922.5 ; + RECT 1462.5 37797.5 2347.5 37732.5 ; + RECT 2347.5 37987.5 2482.5 37922.5 ; + RECT 2347.5 37797.5 2482.5 37732.5 ; + RECT 2347.5 37797.5 2482.5 37732.5 ; + RECT 2347.5 37987.5 2482.5 37922.5 ; + RECT 1462.5 37987.5 1597.5 37922.5 ; + RECT 1462.5 37797.5 1597.5 37732.5 ; + RECT 1462.5 37797.5 1597.5 37732.5 ; + RECT 1462.5 37987.5 1597.5 37922.5 ; + RECT 2437.5 37627.5 2572.5 37562.5 ; + RECT 1462.5 37627.5 1597.5 37562.5 ; + RECT 1905.0 37930.0 2040.0 37865.0 ; + RECT 1905.0 37930.0 2040.0 37865.0 ; + RECT 1940.0 37765.0 2005.0 37700.0 ; + RECT 2657.5 38055.0 2722.5 37495.0 ; + RECT 1312.5 38055.0 1377.5 37495.0 ; + RECT 1905.0 37865.0 2040.0 37930.0 ; + RECT 2505.0 37067.5 2690.0 37002.5 ; + RECT 1345.0 37067.5 1530.0 37002.5 ; + RECT 1462.5 37427.5 1312.5 37362.5 ; + RECT 2347.5 37427.5 2722.5 37362.5 ; + RECT 1462.5 37237.5 2347.5 37172.5 ; + RECT 2347.5 37427.5 2482.5 37362.5 ; + RECT 2347.5 37237.5 2482.5 37172.5 ; + RECT 2347.5 37237.5 2482.5 37172.5 ; + RECT 2347.5 37427.5 2482.5 37362.5 ; + RECT 1462.5 37427.5 1597.5 37362.5 ; + RECT 1462.5 37237.5 1597.5 37172.5 ; + RECT 1462.5 37237.5 1597.5 37172.5 ; + RECT 1462.5 37427.5 1597.5 37362.5 ; + RECT 2437.5 37067.5 2572.5 37002.5 ; + RECT 1462.5 37067.5 1597.5 37002.5 ; + RECT 1905.0 37370.0 2040.0 37305.0 ; + RECT 1905.0 37370.0 2040.0 37305.0 ; + RECT 1940.0 37205.0 2005.0 37140.0 ; + RECT 2657.5 37495.0 2722.5 36935.0 ; + RECT 1312.5 37495.0 1377.5 36935.0 ; + RECT 1905.0 37305.0 2040.0 37370.0 ; + RECT 2505.0 36507.5 2690.0 36442.5 ; + RECT 1345.0 36507.5 1530.0 36442.5 ; + RECT 1462.5 36867.5 1312.5 36802.5 ; + RECT 2347.5 36867.5 2722.5 36802.5 ; + RECT 1462.5 36677.5 2347.5 36612.5 ; + RECT 2347.5 36867.5 2482.5 36802.5 ; + RECT 2347.5 36677.5 2482.5 36612.5 ; + RECT 2347.5 36677.5 2482.5 36612.5 ; + RECT 2347.5 36867.5 2482.5 36802.5 ; + RECT 1462.5 36867.5 1597.5 36802.5 ; + RECT 1462.5 36677.5 1597.5 36612.5 ; + RECT 1462.5 36677.5 1597.5 36612.5 ; + RECT 1462.5 36867.5 1597.5 36802.5 ; + RECT 2437.5 36507.5 2572.5 36442.5 ; + RECT 1462.5 36507.5 1597.5 36442.5 ; + RECT 1905.0 36810.0 2040.0 36745.0 ; + RECT 1905.0 36810.0 2040.0 36745.0 ; + RECT 1940.0 36645.0 2005.0 36580.0 ; + RECT 2657.5 36935.0 2722.5 36375.0 ; + RECT 1312.5 36935.0 1377.5 36375.0 ; + RECT 1905.0 36745.0 2040.0 36810.0 ; + RECT 2505.0 35947.5 2690.0 35882.5 ; + RECT 1345.0 35947.5 1530.0 35882.5 ; + RECT 1462.5 36307.5 1312.5 36242.5 ; + RECT 2347.5 36307.5 2722.5 36242.5 ; + RECT 1462.5 36117.5 2347.5 36052.5 ; + RECT 2347.5 36307.5 2482.5 36242.5 ; + RECT 2347.5 36117.5 2482.5 36052.5 ; + RECT 2347.5 36117.5 2482.5 36052.5 ; + RECT 2347.5 36307.5 2482.5 36242.5 ; + RECT 1462.5 36307.5 1597.5 36242.5 ; + RECT 1462.5 36117.5 1597.5 36052.5 ; + RECT 1462.5 36117.5 1597.5 36052.5 ; + RECT 1462.5 36307.5 1597.5 36242.5 ; + RECT 2437.5 35947.5 2572.5 35882.5 ; + RECT 1462.5 35947.5 1597.5 35882.5 ; + RECT 1905.0 36250.0 2040.0 36185.0 ; + RECT 1905.0 36250.0 2040.0 36185.0 ; + RECT 1940.0 36085.0 2005.0 36020.0 ; + RECT 2657.5 36375.0 2722.5 35815.0 ; + RECT 1312.5 36375.0 1377.5 35815.0 ; + RECT 1905.0 36185.0 2040.0 36250.0 ; + RECT 2505.0 35387.5 2690.0 35322.5 ; + RECT 1345.0 35387.5 1530.0 35322.5 ; + RECT 1462.5 35747.5 1312.5 35682.5 ; + RECT 2347.5 35747.5 2722.5 35682.5 ; + RECT 1462.5 35557.5 2347.5 35492.5 ; + RECT 2347.5 35747.5 2482.5 35682.5 ; + RECT 2347.5 35557.5 2482.5 35492.5 ; + RECT 2347.5 35557.5 2482.5 35492.5 ; + RECT 2347.5 35747.5 2482.5 35682.5 ; + RECT 1462.5 35747.5 1597.5 35682.5 ; + RECT 1462.5 35557.5 1597.5 35492.5 ; + RECT 1462.5 35557.5 1597.5 35492.5 ; + RECT 1462.5 35747.5 1597.5 35682.5 ; + RECT 2437.5 35387.5 2572.5 35322.5 ; + RECT 1462.5 35387.5 1597.5 35322.5 ; + RECT 1905.0 35690.0 2040.0 35625.0 ; + RECT 1905.0 35690.0 2040.0 35625.0 ; + RECT 1940.0 35525.0 2005.0 35460.0 ; + RECT 2657.5 35815.0 2722.5 35255.0 ; + RECT 1312.5 35815.0 1377.5 35255.0 ; + RECT 1905.0 35625.0 2040.0 35690.0 ; RECT 2505.0 34827.5 2690.0 34762.5 ; RECT 1345.0 34827.5 1530.0 34762.5 ; RECT 1462.5 35187.5 1312.5 35122.5 ; @@ -4297,13 +4572,14 @@ MACRO sram_2_16_1_freepdk45 RECT 1312.5 34695.0 1377.5 34135.0 ; RECT 1905.0 34505.0 2040.0 34570.0 ; RECT 3340.0 34425.0 3475.0 34490.0 ; - RECT 3340.0 34985.0 3475.0 35050.0 ; - RECT 1905.0 34900.0 2040.0 34965.0 ; + RECT 3340.0 36665.0 3475.0 36730.0 ; + RECT 3340.0 38905.0 3475.0 38970.0 ; + RECT 1905.0 36580.0 2040.0 36645.0 ; RECT 3340.0 34260.0 3475.0 34325.0 ; RECT 1940.0 34135.0 2005.0 34340.0 ; - RECT 2657.5 34135.0 2722.5 35255.0 ; - RECT 1312.5 34135.0 1377.5 35255.0 ; - RECT 4002.5 34135.0 4067.5 35255.0 ; + RECT 2657.5 34135.0 2722.5 39175.0 ; + RECT 1312.5 34135.0 1377.5 39175.0 ; + RECT 4002.5 34135.0 4067.5 39175.0 ; RECT 935.0 33800.0 225.0 32455.0 ; RECT 935.0 33800.0 230.0 35145.0 ; RECT 935.0 36490.0 230.0 35145.0 ; @@ -4312,12 +4588,12 @@ MACRO sram_2_16_1_freepdk45 RECT 1025.0 35112.5 140.0 35177.5 ; RECT 1025.0 33767.5 140.0 33832.5 ; RECT 1025.0 36457.5 140.0 36522.5 ; - RECT 1377.5 33907.5 1312.5 34042.5 ; - RECT 1377.5 36317.5 1312.5 36452.5 ; - RECT 1377.5 34135.0 1312.5 34270.0 ; + RECT 1345.0 33872.5 1280.0 34007.5 ; + RECT 1345.0 36282.5 1280.0 36417.5 ; + RECT 1342.5 34135.0 1277.5 34270.0 ; RECT 1377.5 31760.0 1312.5 31895.0 ; - RECT 1277.5 36817.5 1412.5 36882.5 ; - RECT 867.5 36817.5 1002.5 36882.5 ; + RECT 867.5 31862.5 1002.5 31927.5 ; + RECT 162.5 31862.5 297.5 31927.5 ; RECT 2005.0 33367.5 1940.0 33502.5 ; RECT 1105.0 32627.5 1240.0 32692.5 ; RECT 1105.0 32030.0 1240.0 32095.0 ; @@ -4326,7 +4602,7 @@ MACRO sram_2_16_1_freepdk45 RECT 2005.0 31335.0 1940.0 32100.0 ; RECT 20.0 31335.0 -45.0 36577.5 ; RECT 2722.5 31335.0 2657.5 34135.0 ; - RECT 1380.0 31335.0 1310.0 32455.0 ; + RECT 1377.5 31335.0 1312.5 31895.0 ; RECT 4067.5 31335.0 4002.5 34135.0 ; RECT 3455.0 26182.5 3390.0 26047.5 ; RECT 3455.0 22102.5 3390.0 21967.5 ; @@ -4529,14 +4805,14 @@ MACRO sram_2_16_1_freepdk45 RECT 9057.5 11120.0 9192.5 11190.0 ; RECT 10717.5 12465.0 10852.5 12535.0 ; RECT 8782.5 12465.0 8917.5 12535.0 ; - RECT 9607.5 8720.0 9742.5 8790.0 ; - RECT 9332.5 8935.0 9467.5 9005.0 ; - RECT 9057.5 10560.0 9192.5 10630.0 ; - RECT 9332.5 10345.0 9467.5 10415.0 ; - RECT 9607.5 11410.0 9742.5 11480.0 ; - RECT 8782.5 11625.0 8917.5 11695.0 ; - RECT 9057.5 13250.0 9192.5 13320.0 ; - RECT 8782.5 13035.0 8917.5 13105.0 ; + RECT 9607.5 8935.0 9742.5 9005.0 ; + RECT 9332.5 8720.0 9467.5 8790.0 ; + RECT 9057.5 10345.0 9192.5 10415.0 ; + RECT 9332.5 10560.0 9467.5 10630.0 ; + RECT 9607.5 11625.0 9742.5 11695.0 ; + RECT 8782.5 11410.0 8917.5 11480.0 ; + RECT 9057.5 13035.0 9192.5 13105.0 ; + RECT 8782.5 13250.0 8917.5 13320.0 ; RECT 11095.0 8330.0 11025.0 13570.0 ; RECT 10820.0 8330.0 10750.0 13570.0 ; RECT 9160.0 13710.0 9090.0 18950.0 ; @@ -4583,14 +4859,14 @@ MACRO sram_2_16_1_freepdk45 RECT 9057.5 16500.0 9192.5 16570.0 ; RECT 10717.5 17845.0 10852.5 17915.0 ; RECT 8782.5 17845.0 8917.5 17915.0 ; - RECT 9607.5 14100.0 9742.5 14170.0 ; - RECT 9332.5 14315.0 9467.5 14385.0 ; - RECT 9057.5 15940.0 9192.5 16010.0 ; - RECT 9332.5 15725.0 9467.5 15795.0 ; - RECT 9607.5 16790.0 9742.5 16860.0 ; - RECT 8782.5 17005.0 8917.5 17075.0 ; - RECT 9057.5 18630.0 9192.5 18700.0 ; - RECT 8782.5 18415.0 8917.5 18485.0 ; + RECT 9607.5 14315.0 9742.5 14385.0 ; + RECT 9332.5 14100.0 9467.5 14170.0 ; + RECT 9057.5 15725.0 9192.5 15795.0 ; + RECT 9332.5 15940.0 9467.5 16010.0 ; + RECT 9607.5 17005.0 9742.5 17075.0 ; + RECT 8782.5 16790.0 8917.5 16860.0 ; + RECT 9057.5 18415.0 9192.5 18485.0 ; + RECT 8782.5 18630.0 8917.5 18700.0 ; RECT 11095.0 13710.0 11025.0 18950.0 ; RECT 10820.0 13710.0 10750.0 18950.0 ; RECT 7385.0 19695.0 7455.0 19765.0 ; @@ -5088,6 +5364,7 @@ MACRO sram_2_16_1_freepdk45 RECT 4035.0 26695.0 8.881784197e-13 26765.0 ; RECT 4035.0 26900.0 8.881784197e-13 26970.0 ; RECT 4035.0 27310.0 8.881784197e-13 27380.0 ; + RECT 3422.5 22000.0 2690.0 22070.0 ; RECT 2520.0 19467.5 2450.0 26115.0 ; RECT 4035.0 26285.0 3830.0 26355.0 ; RECT 2895.0 27105.0 2690.0 27175.0 ; @@ -5162,25 +5439,51 @@ MACRO sram_2_16_1_freepdk45 RECT 1610.0 26387.5 1540.0 26252.5 ; RECT 2315.0 25737.5 2245.0 25602.5 ; RECT 2315.0 26387.5 2245.0 26252.5 ; - RECT 1380.0 31895.0 1310.0 36750.0 ; - RECT 1380.0 32455.0 1310.0 32660.0 ; - RECT 1380.0 32660.0 1310.0 36850.0 ; - RECT 970.0 36645.0 900.0 36850.0 ; + RECT 1380.0 31895.0 1310.0 36955.0 ; + RECT 970.0 31895.0 900.0 36645.0 ; + RECT 265.0 31895.0 195.0 36645.0 ; RECT 1207.5 32062.5 1137.5 32660.0 ; RECT 785.0 32062.5 715.0 32342.5 ; RECT 3372.5 34457.5 3442.5 34852.5 ; - RECT 2655.0 34982.5 2725.0 35052.5 ; - RECT 2655.0 35062.5 2725.0 35132.5 ; - RECT 2690.0 34982.5 3407.5 35052.5 ; - RECT 2655.0 35017.5 2725.0 35097.5 ; - RECT 1972.5 35062.5 2690.0 35132.5 ; - RECT 1937.5 34537.5 2007.5 34932.5 ; + RECT 3372.5 34852.5 3442.5 35412.5 ; + RECT 3372.5 35412.5 3442.5 35972.5 ; + RECT 3372.5 35972.5 3442.5 36532.5 ; + RECT 3372.5 36697.5 3442.5 37092.5 ; + RECT 3372.5 37092.5 3442.5 37652.5 ; + RECT 3372.5 37652.5 3442.5 38212.5 ; + RECT 3372.5 38212.5 3442.5 38772.5 ; + RECT 2655.0 38902.5 2725.0 38972.5 ; + RECT 2655.0 38422.5 2725.0 38492.5 ; + RECT 2690.0 38902.5 3407.5 38972.5 ; + RECT 2655.0 38457.5 2725.0 38937.5 ; + RECT 1972.5 38422.5 2690.0 38492.5 ; + RECT 1937.5 37897.5 2007.5 38457.5 ; + RECT 1937.5 37337.5 2007.5 37897.5 ; + RECT 1937.5 36777.5 2007.5 37337.5 ; + RECT 1937.5 36217.5 2007.5 36612.5 ; + RECT 1937.5 35657.5 2007.5 36217.5 ; + RECT 1937.5 35097.5 2007.5 35657.5 ; + RECT 1937.5 34537.5 2007.5 35097.5 ; RECT 3340.0 34817.5 3475.0 34887.5 ; + RECT 3340.0 35377.5 3475.0 35447.5 ; + RECT 3340.0 35937.5 3475.0 36007.5 ; + RECT 3340.0 36497.5 3475.0 36567.5 ; + RECT 3340.0 37057.5 3475.0 37127.5 ; + RECT 3340.0 37617.5 3475.0 37687.5 ; + RECT 3340.0 38177.5 3475.0 38247.5 ; + RECT 3340.0 38737.5 3475.0 38807.5 ; + RECT 1905.0 38422.5 2040.0 38492.5 ; + RECT 1905.0 37862.5 2040.0 37932.5 ; + RECT 1905.0 37302.5 2040.0 37372.5 ; + RECT 1905.0 36742.5 2040.0 36812.5 ; + RECT 1905.0 36182.5 2040.0 36252.5 ; + RECT 1905.0 35622.5 2040.0 35692.5 ; RECT 1905.0 35062.5 2040.0 35132.5 ; RECT 1905.0 34502.5 2040.0 34572.5 ; RECT 3340.0 34422.5 3475.0 34492.5 ; - RECT 3340.0 34982.5 3475.0 35052.5 ; - RECT 1905.0 34897.5 2040.0 34967.5 ; + RECT 3340.0 36662.5 3475.0 36732.5 ; + RECT 3340.0 38902.5 3475.0 38972.5 ; + RECT 1905.0 36577.5 2040.0 36647.5 ; RECT 935.0 33800.0 225.0 32455.0 ; RECT 935.0 33800.0 230.0 35145.0 ; RECT 935.0 36490.0 230.0 35145.0 ; @@ -5188,19 +5491,19 @@ MACRO sram_2_16_1_freepdk45 RECT 450.0 33700.0 380.0 36645.0 ; RECT 970.0 33700.0 900.0 36645.0 ; RECT 265.0 33700.0 195.0 36645.0 ; - RECT 1380.0 33907.5 1310.0 34042.5 ; - RECT 1380.0 36317.5 1310.0 36452.5 ; - RECT 1380.0 34135.0 1310.0 34270.0 ; + RECT 1347.5 33872.5 1277.5 34007.5 ; + RECT 1347.5 36282.5 1277.5 36417.5 ; + RECT 1345.0 34135.0 1275.0 34270.0 ; RECT 1380.0 31760.0 1310.0 31895.0 ; - RECT 1277.5 36815.0 1412.5 36885.0 ; - RECT 867.5 36815.0 1002.5 36885.0 ; + RECT 867.5 31860.0 1002.5 31930.0 ; + RECT 162.5 31860.0 297.5 31930.0 ; RECT 1105.0 32625.0 1240.0 32695.0 ; RECT 1105.0 32027.5 1240.0 32097.5 ; RECT 682.5 32027.5 817.5 32097.5 ; RECT 3457.5 26182.5 3387.5 26047.5 ; RECT 3457.5 22102.5 3387.5 21967.5 ; - RECT 3457.5 27617.5 3387.5 27482.5 ; - RECT 3457.5 22102.5 3387.5 21967.5 ; + RECT 2725.0 22102.5 2655.0 21967.5 ; + RECT 2725.0 27617.5 2655.0 27482.5 ; RECT 2520.0 19535.0 2450.0 19400.0 ; RECT 1965.0 26182.5 1895.0 26047.5 ; RECT 1750.0 26592.5 1680.0 26457.5 ; @@ -5299,7 +5602,7 @@ MACRO sram_2_16_1_freepdk45 RECT 905.0 25670.0 835.0 26320.0 ; RECT 1610.0 25670.0 1540.0 26320.0 ; RECT 2315.0 25670.0 2245.0 26320.0 ; - RECT 3457.5 22035.0 3387.5 27550.0 ; + RECT 2725.0 22035.0 2655.0 27550.0 ; RECT 2020.0 27550.0 1950.0 29062.5 ; RECT 1805.0 27345.0 1735.0 29320.0 ; RECT 482.5 19230.0 552.5 19370.0 ; @@ -5321,8 +5624,8 @@ MACRO sram_2_16_1_freepdk45 RECT 1610.0 26387.5 1540.0 26252.5 ; RECT 2315.0 25737.5 2245.0 25602.5 ; RECT 2315.0 26387.5 2245.0 26252.5 ; - RECT 3457.5 22102.5 3387.5 21967.5 ; - RECT 3457.5 27617.5 3387.5 27482.5 ; + RECT 2725.0 22102.5 2655.0 21967.5 ; + RECT 2725.0 27617.5 2655.0 27482.5 ; RECT 2020.0 29130.0 1950.0 28995.0 ; RECT 2020.0 27617.5 1950.0 27482.5 ; RECT 1805.0 29387.5 1735.0 29252.5 ; diff --git a/compiler/tests/golden/sram_2_16_1_scn3me_subm_pruned.lib b/compiler/tests/golden/sram_2_16_1_freepdk45_TT_10V_25C.lib similarity index 65% rename from compiler/tests/golden/sram_2_16_1_scn3me_subm_pruned.lib rename to compiler/tests/golden/sram_2_16_1_freepdk45_TT_10V_25C.lib index 81a87cd8..68458eba 100644 --- a/compiler/tests/golden/sram_2_16_1_scn3me_subm_pruned.lib +++ b/compiler/tests/golden/sram_2_16_1_freepdk45_TT_10V_25C.lib @@ -1,4 +1,4 @@ -library (sram_2_16_1_scn3me_subm_lib){ +library (sram_2_16_1_freepdk45_TT_10V_25C_lib){ delay_model : "table_lookup"; time_unit : "1ns" ; voltage_unit : "1v" ; @@ -8,8 +8,8 @@ library (sram_2_16_1_scn3me_subm_lib){ leakage_power_unit : "1mW" ; pulling_resistance_unit :"1kohm" ; operating_conditions(TT){ - voltage : 5.0 ; - temperature : 25.000 ; + voltage : 1.0 ; + temperature : 25; } input_threshold_pct_fall : 50.0 ; @@ -34,15 +34,15 @@ library (sram_2_16_1_scn3me_subm_lib){ lu_table_template(CELL_TABLE){ variable_1 : input_net_transition; variable_2 : total_output_net_capacitance; - index_1("0.0125, 0.05, 0.4"); - index_2("2.45605, 9.8242, 78.5936"); + index_1("0.00125, 0.005, 0.04"); + index_2("0.052275, 0.2091, 1.6728"); } lu_table_template(CONSTRAINT_TABLE){ variable_1 : related_pin_transition; variable_2 : constrained_pin_transition; - index_1("0.0125, 0.05, 0.4"); - index_2("0.0125, 0.05, 0.4"); + index_1("0.00125, 0.005, 0.04"); + index_2("0.00125, 0.005, 0.04"); } default_operating_conditions : TT; @@ -64,7 +64,7 @@ library (sram_2_16_1_scn3me_subm_lib){ bit_to : 3; } -cell (sram_2_16_1_scn3me_subm){ +cell (sram_2_16_1_freepdk45){ memory(){ type : ram; address_width : 4; @@ -74,12 +74,12 @@ cell (sram_2_16_1_scn3me_subm){ dont_use : true; map_only : true; dont_touch : true; - area : 2.7; + area : 918.5120625; bus(DATA){ bus_type : DATA; direction : inout; - max_capacitance : 78.5936; + max_capacitance : 1.6728; three_state : "!OEb & !clk"; memory_write(){ address : ADDR; @@ -92,47 +92,47 @@ cell (sram_2_16_1_scn3me_subm){ internal_power(){ when : "OEb & !clk"; rise_power(scalar){ - values("2.8745"); + values("0.042347092"); } fall_power(scalar){ - values("3.0265"); + values("0.029908723"); } } timing(){ timing_type : setup_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.082, 0.088, 0.186",\ - "0.082, 0.088, 0.186",\ - "0.082, 0.088, 0.186"); + values("0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021"); } fall_constraint(CONSTRAINT_TABLE) { - values("0.021, 0.021, 0.027",\ - "0.021, 0.021, 0.027",\ - "0.021, 0.021, 0.027"); + values("0.009, 0.009, 0.015",\ + "0.009, 0.009, 0.015",\ + "0.009, 0.009, 0.015"); } } timing(){ timing_type : hold_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.015, 0.021",\ - "0.009, 0.015, 0.021",\ - "0.009, 0.015, 0.021"); + values("0.002, 0.002, -0.004",\ + "0.002, 0.002, -0.004",\ + "0.002, 0.002, -0.004"); } fall_constraint(CONSTRAINT_TABLE) { - values("-0.065, -0.071, -0.175",\ - "-0.065, -0.071, -0.175",\ - "-0.065, -0.071, -0.175"); + values("-0.004, -0.004, -0.016",\ + "-0.004, -0.004, -0.016",\ + "-0.004, -0.004, -0.016"); } } internal_power(){ when : "!OEb & !clk"; rise_power(scalar){ - values("4.4921"); + values("0.054779642"); } fall_power(scalar){ - values("4.5139"); + values("0.060081573"); } } timing(){ @@ -140,24 +140,24 @@ cell (sram_2_16_1_scn3me_subm){ related_pin : "clk"; timing_type : falling_edge; cell_rise(CELL_TABLE) { - values("0.496, 0.579, 1.253",\ - "0.499, 0.581, 1.258",\ - "0.547, 0.627, 1.305"); + values("0.055, 0.056, 0.063",\ + "0.056, 0.057, 0.063",\ + "0.061, 0.062, 0.069"); } cell_fall(CELL_TABLE) { - values("1.429, 1.539, 2.523",\ - "1.433, 1.544, 2.526",\ - "1.485, 1.595, 2.578"); + values("0.522, 0.523, 0.533",\ + "0.523, 0.524, 0.533",\ + "0.528, 0.529, 0.539"); } rise_transition(CELL_TABLE) { - values("0.189, 0.335, 1.879",\ - "0.19, 0.336, 1.879",\ - "0.192, 0.337, 1.879"); + values("0.013, 0.015, 0.026",\ + "0.013, 0.015, 0.026",\ + "0.013, 0.015, 0.026"); } fall_transition(CELL_TABLE) { - values("0.224, 0.437, 2.462",\ - "0.225, 0.437, 2.472",\ - "0.225, 0.436, 2.458"); + values("0.029, 0.031, 0.044",\ + "0.029, 0.031, 0.044",\ + "0.029, 0.031, 0.044"); } } } @@ -166,36 +166,36 @@ cell (sram_2_16_1_scn3me_subm){ bus(ADDR){ bus_type : ADDR; direction : input; - capacitance : 9.8242; - max_transition : 0.4; + capacitance : 0.2091; + max_transition : 0.04; fanout_load : 1.000000; pin(ADDR[3:0]){ timing(){ timing_type : setup_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.082, 0.088, 0.186",\ - "0.082, 0.088, 0.186",\ - "0.082, 0.088, 0.186"); + values("0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021"); } fall_constraint(CONSTRAINT_TABLE) { - values("0.021, 0.021, 0.027",\ - "0.021, 0.021, 0.027",\ - "0.021, 0.021, 0.027"); + values("0.009, 0.009, 0.015",\ + "0.009, 0.009, 0.015",\ + "0.009, 0.009, 0.015"); } } timing(){ timing_type : hold_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.015, 0.021",\ - "0.009, 0.015, 0.021",\ - "0.009, 0.015, 0.021"); + values("0.002, 0.002, -0.004",\ + "0.002, 0.002, -0.004",\ + "0.002, 0.002, -0.004"); } fall_constraint(CONSTRAINT_TABLE) { - values("-0.065, -0.071, -0.175",\ - "-0.065, -0.071, -0.175",\ - "-0.065, -0.071, -0.175"); + values("-0.004, -0.004, -0.016",\ + "-0.004, -0.004, -0.016",\ + "-0.004, -0.004, -0.016"); } } } @@ -203,99 +203,99 @@ cell (sram_2_16_1_scn3me_subm){ pin(CSb){ direction : input; - capacitance : 9.8242; + capacitance : 0.2091; timing(){ timing_type : setup_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.082, 0.088, 0.186",\ - "0.082, 0.088, 0.186",\ - "0.082, 0.088, 0.186"); + values("0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021"); } fall_constraint(CONSTRAINT_TABLE) { - values("0.021, 0.021, 0.027",\ - "0.021, 0.021, 0.027",\ - "0.021, 0.021, 0.027"); + values("0.009, 0.009, 0.015",\ + "0.009, 0.009, 0.015",\ + "0.009, 0.009, 0.015"); } } timing(){ timing_type : hold_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.015, 0.021",\ - "0.009, 0.015, 0.021",\ - "0.009, 0.015, 0.021"); + values("0.002, 0.002, -0.004",\ + "0.002, 0.002, -0.004",\ + "0.002, 0.002, -0.004"); } fall_constraint(CONSTRAINT_TABLE) { - values("-0.065, -0.071, -0.175",\ - "-0.065, -0.071, -0.175",\ - "-0.065, -0.071, -0.175"); + values("-0.004, -0.004, -0.016",\ + "-0.004, -0.004, -0.016",\ + "-0.004, -0.004, -0.016"); } } } pin(OEb){ direction : input; - capacitance : 9.8242; + capacitance : 0.2091; timing(){ timing_type : setup_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.082, 0.088, 0.186",\ - "0.082, 0.088, 0.186",\ - "0.082, 0.088, 0.186"); + values("0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021"); } fall_constraint(CONSTRAINT_TABLE) { - values("0.021, 0.021, 0.027",\ - "0.021, 0.021, 0.027",\ - "0.021, 0.021, 0.027"); + values("0.009, 0.009, 0.015",\ + "0.009, 0.009, 0.015",\ + "0.009, 0.009, 0.015"); } } timing(){ timing_type : hold_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.015, 0.021",\ - "0.009, 0.015, 0.021",\ - "0.009, 0.015, 0.021"); + values("0.002, 0.002, -0.004",\ + "0.002, 0.002, -0.004",\ + "0.002, 0.002, -0.004"); } fall_constraint(CONSTRAINT_TABLE) { - values("-0.065, -0.071, -0.175",\ - "-0.065, -0.071, -0.175",\ - "-0.065, -0.071, -0.175"); + values("-0.004, -0.004, -0.016",\ + "-0.004, -0.004, -0.016",\ + "-0.004, -0.004, -0.016"); } } } pin(WEb){ direction : input; - capacitance : 9.8242; + capacitance : 0.2091; timing(){ timing_type : setup_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.082, 0.088, 0.186",\ - "0.082, 0.088, 0.186",\ - "0.082, 0.088, 0.186"); + values("0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021"); } fall_constraint(CONSTRAINT_TABLE) { - values("0.021, 0.021, 0.027",\ - "0.021, 0.021, 0.027",\ - "0.021, 0.021, 0.027"); + values("0.009, 0.009, 0.015",\ + "0.009, 0.009, 0.015",\ + "0.009, 0.009, 0.015"); } } timing(){ timing_type : hold_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.015, 0.021",\ - "0.009, 0.015, 0.021",\ - "0.009, 0.015, 0.021"); + values("0.002, 0.002, -0.004",\ + "0.002, 0.002, -0.004",\ + "0.002, 0.002, -0.004"); } fall_constraint(CONSTRAINT_TABLE) { - values("-0.065, -0.071, -0.175",\ - "-0.065, -0.071, -0.175",\ - "-0.065, -0.071, -0.175"); + values("-0.004, -0.004, -0.016",\ + "-0.004, -0.004, -0.016",\ + "-0.004, -0.004, -0.016"); } } } @@ -303,25 +303,25 @@ cell (sram_2_16_1_scn3me_subm){ pin(clk){ clock : true; direction : input; - capacitance : 9.8242; + capacitance : 0.2091; timing(){ timing_type :"min_pulse_width"; related_pin : clk; rise_constraint(scalar) { - values("4.375"); + values("0.5275"); } fall_constraint(scalar) { - values("4.375"); + values("0.5275"); } } timing(){ timing_type :"minimum_period"; related_pin : clk; rise_constraint(scalar) { - values("8.75"); + values("1.055"); } fall_constraint(scalar) { - values("8.75"); + values("1.055"); } } } diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45.lib b/compiler/tests/golden/sram_2_16_1_freepdk45_TT_10V_25C_analytical.lib similarity index 84% rename from compiler/tests/golden/sram_2_16_1_freepdk45.lib rename to compiler/tests/golden/sram_2_16_1_freepdk45_TT_10V_25C_analytical.lib index 2460f1a1..22715e9f 100644 --- a/compiler/tests/golden/sram_2_16_1_freepdk45.lib +++ b/compiler/tests/golden/sram_2_16_1_freepdk45_TT_10V_25C_analytical.lib @@ -1,4 +1,4 @@ -library (sram_2_16_1_freepdk45_lib){ +library (sram_2_16_1_freepdk45_TT_10V_25C_lib){ delay_model : "table_lookup"; time_unit : "1ns" ; voltage_unit : "1v" ; @@ -9,7 +9,7 @@ library (sram_2_16_1_freepdk45_lib){ pulling_resistance_unit :"1kohm" ; operating_conditions(TT){ voltage : 1.0 ; - temperature : 25.000 ; + temperature : 25; } input_threshold_pct_fall : 50.0 ; @@ -74,7 +74,7 @@ cell (sram_2_16_1_freepdk45){ dont_use : true; map_only : true; dont_touch : true; - area : 0.023625; + area : 918.5120625; bus(DATA){ bus_type : DATA; @@ -92,19 +92,19 @@ cell (sram_2_16_1_freepdk45){ internal_power(){ when : "OEb & !clk"; rise_power(scalar){ - values("0.027781"); + values("0.039115101"); } fall_power(scalar){ - values("0.026752"); + values("0.026662611"); } } timing(){ timing_type : setup_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027"); + values("0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021"); } fall_constraint(CONSTRAINT_TABLE) { values("0.009, 0.009, 0.015",\ @@ -129,10 +129,10 @@ cell (sram_2_16_1_freepdk45){ internal_power(){ when : "!OEb & !clk"; rise_power(scalar){ - values("0.031198"); + values("0.036300681"); } fall_power(scalar){ - values("0.031252"); + values("0.041472985"); } } timing(){ @@ -140,24 +140,24 @@ cell (sram_2_16_1_freepdk45){ related_pin : "clk"; timing_type : falling_edge; cell_rise(CELL_TABLE) { - values("0.046, 0.047, 0.054",\ - "0.047, 0.047, 0.054",\ - "0.052, 0.052, 0.059"); + values("0.054, 0.055, 0.061",\ + "0.055, 0.055, 0.062",\ + "0.06, 0.061, 0.067"); } cell_fall(CELL_TABLE) { - values("0.132, 0.133, 0.142",\ - "0.133, 0.134, 0.142",\ - "0.138, 0.139, 0.147"); + values("0.519, 0.52, 0.529",\ + "0.519, 0.52, 0.53",\ + "0.525, 0.526, 0.535"); } rise_transition(CELL_TABLE) { - values("0.014, 0.015, 0.027",\ - "0.014, 0.015, 0.027",\ - "0.014, 0.015, 0.027"); + values("0.013, 0.014, 0.026",\ + "0.013, 0.014, 0.026",\ + "0.013, 0.015, 0.026"); } fall_transition(CELL_TABLE) { - values("0.018, 0.02, 0.036",\ - "0.019, 0.02, 0.036",\ - "0.019, 0.02, 0.036"); + values("0.027, 0.029, 0.043",\ + "0.027, 0.029, 0.043",\ + "0.027, 0.029, 0.043"); } } } @@ -174,9 +174,9 @@ cell (sram_2_16_1_freepdk45){ timing_type : setup_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027"); + values("0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021"); } fall_constraint(CONSTRAINT_TABLE) { values("0.009, 0.009, 0.015",\ @@ -208,9 +208,9 @@ cell (sram_2_16_1_freepdk45){ timing_type : setup_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027"); + values("0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021"); } fall_constraint(CONSTRAINT_TABLE) { values("0.009, 0.009, 0.015",\ @@ -241,9 +241,9 @@ cell (sram_2_16_1_freepdk45){ timing_type : setup_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027"); + values("0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021"); } fall_constraint(CONSTRAINT_TABLE) { values("0.009, 0.009, 0.015",\ @@ -274,9 +274,9 @@ cell (sram_2_16_1_freepdk45){ timing_type : setup_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027"); + values("0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021"); } fall_constraint(CONSTRAINT_TABLE) { values("0.009, 0.009, 0.015",\ @@ -308,20 +308,20 @@ cell (sram_2_16_1_freepdk45){ timing_type :"min_pulse_width"; related_pin : clk; rise_constraint(scalar) { - values("0.1955"); + values("0.5275"); } fall_constraint(scalar) { - values("0.1955"); + values("0.5275"); } } timing(){ timing_type :"minimum_period"; related_pin : clk; rise_constraint(scalar) { - values("0.391"); + values("1.055"); } fall_constraint(scalar) { - values("0.391"); + values("1.055"); } } } diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45_pruned.lib b/compiler/tests/golden/sram_2_16_1_freepdk45_TT_10V_25C_pruned.lib similarity index 84% rename from compiler/tests/golden/sram_2_16_1_freepdk45_pruned.lib rename to compiler/tests/golden/sram_2_16_1_freepdk45_TT_10V_25C_pruned.lib index 2460f1a1..22715e9f 100644 --- a/compiler/tests/golden/sram_2_16_1_freepdk45_pruned.lib +++ b/compiler/tests/golden/sram_2_16_1_freepdk45_TT_10V_25C_pruned.lib @@ -1,4 +1,4 @@ -library (sram_2_16_1_freepdk45_lib){ +library (sram_2_16_1_freepdk45_TT_10V_25C_lib){ delay_model : "table_lookup"; time_unit : "1ns" ; voltage_unit : "1v" ; @@ -9,7 +9,7 @@ library (sram_2_16_1_freepdk45_lib){ pulling_resistance_unit :"1kohm" ; operating_conditions(TT){ voltage : 1.0 ; - temperature : 25.000 ; + temperature : 25; } input_threshold_pct_fall : 50.0 ; @@ -74,7 +74,7 @@ cell (sram_2_16_1_freepdk45){ dont_use : true; map_only : true; dont_touch : true; - area : 0.023625; + area : 918.5120625; bus(DATA){ bus_type : DATA; @@ -92,19 +92,19 @@ cell (sram_2_16_1_freepdk45){ internal_power(){ when : "OEb & !clk"; rise_power(scalar){ - values("0.027781"); + values("0.039115101"); } fall_power(scalar){ - values("0.026752"); + values("0.026662611"); } } timing(){ timing_type : setup_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027"); + values("0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021"); } fall_constraint(CONSTRAINT_TABLE) { values("0.009, 0.009, 0.015",\ @@ -129,10 +129,10 @@ cell (sram_2_16_1_freepdk45){ internal_power(){ when : "!OEb & !clk"; rise_power(scalar){ - values("0.031198"); + values("0.036300681"); } fall_power(scalar){ - values("0.031252"); + values("0.041472985"); } } timing(){ @@ -140,24 +140,24 @@ cell (sram_2_16_1_freepdk45){ related_pin : "clk"; timing_type : falling_edge; cell_rise(CELL_TABLE) { - values("0.046, 0.047, 0.054",\ - "0.047, 0.047, 0.054",\ - "0.052, 0.052, 0.059"); + values("0.054, 0.055, 0.061",\ + "0.055, 0.055, 0.062",\ + "0.06, 0.061, 0.067"); } cell_fall(CELL_TABLE) { - values("0.132, 0.133, 0.142",\ - "0.133, 0.134, 0.142",\ - "0.138, 0.139, 0.147"); + values("0.519, 0.52, 0.529",\ + "0.519, 0.52, 0.53",\ + "0.525, 0.526, 0.535"); } rise_transition(CELL_TABLE) { - values("0.014, 0.015, 0.027",\ - "0.014, 0.015, 0.027",\ - "0.014, 0.015, 0.027"); + values("0.013, 0.014, 0.026",\ + "0.013, 0.014, 0.026",\ + "0.013, 0.015, 0.026"); } fall_transition(CELL_TABLE) { - values("0.018, 0.02, 0.036",\ - "0.019, 0.02, 0.036",\ - "0.019, 0.02, 0.036"); + values("0.027, 0.029, 0.043",\ + "0.027, 0.029, 0.043",\ + "0.027, 0.029, 0.043"); } } } @@ -174,9 +174,9 @@ cell (sram_2_16_1_freepdk45){ timing_type : setup_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027"); + values("0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021"); } fall_constraint(CONSTRAINT_TABLE) { values("0.009, 0.009, 0.015",\ @@ -208,9 +208,9 @@ cell (sram_2_16_1_freepdk45){ timing_type : setup_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027"); + values("0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021"); } fall_constraint(CONSTRAINT_TABLE) { values("0.009, 0.009, 0.015",\ @@ -241,9 +241,9 @@ cell (sram_2_16_1_freepdk45){ timing_type : setup_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027"); + values("0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021"); } fall_constraint(CONSTRAINT_TABLE) { values("0.009, 0.009, 0.015",\ @@ -274,9 +274,9 @@ cell (sram_2_16_1_freepdk45){ timing_type : setup_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027",\ - "0.009, 0.015, 0.027"); + values("0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021",\ + "0.009, 0.015, 0.021"); } fall_constraint(CONSTRAINT_TABLE) { values("0.009, 0.009, 0.015",\ @@ -308,20 +308,20 @@ cell (sram_2_16_1_freepdk45){ timing_type :"min_pulse_width"; related_pin : clk; rise_constraint(scalar) { - values("0.1955"); + values("0.5275"); } fall_constraint(scalar) { - values("0.1955"); + values("0.5275"); } } timing(){ timing_type :"minimum_period"; related_pin : clk; rise_constraint(scalar) { - values("0.391"); + values("1.055"); } fall_constraint(scalar) { - values("0.391"); + values("1.055"); } } } diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45_analytical.lib b/compiler/tests/golden/sram_2_16_1_freepdk45_analytical.lib deleted file mode 100644 index aefe3d94..00000000 --- a/compiler/tests/golden/sram_2_16_1_freepdk45_analytical.lib +++ /dev/null @@ -1,329 +0,0 @@ -library (sram_2_16_1_freepdk45_lib){ - delay_model : "table_lookup"; - time_unit : "1ns" ; - voltage_unit : "1v" ; - current_unit : "1mA" ; - resistance_unit : "1kohm" ; - capacitive_load_unit(1 ,fF) ; - leakage_power_unit : "1mW" ; - pulling_resistance_unit :"1kohm" ; - operating_conditions(TT){ - voltage : 1.0 ; - temperature : 25.000 ; - } - - input_threshold_pct_fall : 50.0 ; - output_threshold_pct_fall : 50.0 ; - input_threshold_pct_rise : 50.0 ; - output_threshold_pct_rise : 50.0 ; - slew_lower_threshold_pct_fall : 10.0 ; - slew_upper_threshold_pct_fall : 90.0 ; - slew_lower_threshold_pct_rise : 10.0 ; - slew_upper_threshold_pct_rise : 90.0 ; - - default_cell_leakage_power : 0.0 ; - default_leakage_power_density : 0.0 ; - default_input_pin_cap : 1.0 ; - default_inout_pin_cap : 1.0 ; - default_output_pin_cap : 0.0 ; - default_max_transition : 0.5 ; - default_fanout_load : 1.0 ; - default_max_fanout : 4.0 ; - default_connection_class : universal ; - - lu_table_template(CELL_TABLE){ - variable_1 : input_net_transition; - variable_2 : total_output_net_capacitance; - index_1("0.00125, 0.005, 0.04"); - index_2("0.052275, 0.2091, 1.6728"); - } - - lu_table_template(CONSTRAINT_TABLE){ - variable_1 : related_pin_transition; - variable_2 : constrained_pin_transition; - index_1("0.00125, 0.005, 0.04"); - index_2("0.00125, 0.005, 0.04"); - } - - default_operating_conditions : TT; - - - type (DATA){ - base_type : array; - data_type : bit; - bit_width : 2; - bit_from : 0; - bit_to : 1; - } - - type (ADDR){ - base_type : array; - data_type : bit; - bit_width : 4; - bit_from : 0; - bit_to : 3; - } - -cell (sram_2_16_1_freepdk45){ - memory(){ - type : ram; - address_width : 4; - word_width : 2; - } - interface_timing : true; - dont_use : true; - map_only : true; - dont_touch : true; - area : 0.023625; - - bus(DATA){ - bus_type : DATA; - direction : inout; - max_capacitance : 1.6728; - three_state : "!OEb & !clk"; - memory_write(){ - address : ADDR; - clocked_on : clk; - } - memory_read(){ - address : ADDR; - } - pin(DATA[1:0]){ - internal_power(){ - when : "OEb & !clk"; - rise_power(scalar){ - values("0"); - } - fall_power(scalar){ - values("0"); - } - } - timing(){ - timing_type : setup_rising; - related_pin : "clk"; - rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009"); - } - fall_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009"); - } - } - timing(){ - timing_type : hold_rising; - related_pin : "clk"; - rise_constraint(CONSTRAINT_TABLE) { - values("0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001"); - } - fall_constraint(CONSTRAINT_TABLE) { - values("0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001"); - } - } - internal_power(){ - when : "!OEb & !clk"; - rise_power(scalar){ - values("0"); - } - fall_power(scalar){ - values("0"); - } - } - timing(){ - timing_sense : non_unate; - related_pin : "clk"; - timing_type : falling_edge; - cell_rise(CELL_TABLE) { - values("0.123, 0.124, 0.133",\ - "0.123, 0.124, 0.133",\ - "0.123, 0.124, 0.133"); - } - cell_fall(CELL_TABLE) { - values("0.123, 0.124, 0.133",\ - "0.123, 0.124, 0.133",\ - "0.123, 0.124, 0.133"); - } - rise_transition(CELL_TABLE) { - values("0.006, 0.007, 0.018",\ - "0.006, 0.007, 0.018",\ - "0.006, 0.007, 0.018"); - } - fall_transition(CELL_TABLE) { - values("0.006, 0.007, 0.018",\ - "0.006, 0.007, 0.018",\ - "0.006, 0.007, 0.018"); - } - } - } - } - - bus(ADDR){ - bus_type : ADDR; - direction : input; - capacitance : 0.2091; - max_transition : 0.04; - fanout_load : 1.000000; - pin(ADDR[3:0]){ - timing(){ - timing_type : setup_rising; - related_pin : "clk"; - rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009"); - } - fall_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009"); - } - } - timing(){ - timing_type : hold_rising; - related_pin : "clk"; - rise_constraint(CONSTRAINT_TABLE) { - values("0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001"); - } - fall_constraint(CONSTRAINT_TABLE) { - values("0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001"); - } - } - } - } - - pin(CSb){ - direction : input; - capacitance : 0.2091; - timing(){ - timing_type : setup_rising; - related_pin : "clk"; - rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009"); - } - fall_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009"); - } - } - timing(){ - timing_type : hold_rising; - related_pin : "clk"; - rise_constraint(CONSTRAINT_TABLE) { - values("0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001"); - } - fall_constraint(CONSTRAINT_TABLE) { - values("0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001"); - } - } - } - - pin(OEb){ - direction : input; - capacitance : 0.2091; - timing(){ - timing_type : setup_rising; - related_pin : "clk"; - rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009"); - } - fall_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009"); - } - } - timing(){ - timing_type : hold_rising; - related_pin : "clk"; - rise_constraint(CONSTRAINT_TABLE) { - values("0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001"); - } - fall_constraint(CONSTRAINT_TABLE) { - values("0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001"); - } - } - } - - pin(WEb){ - direction : input; - capacitance : 0.2091; - timing(){ - timing_type : setup_rising; - related_pin : "clk"; - rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009"); - } - fall_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009",\ - "0.009, 0.009, 0.009"); - } - } - timing(){ - timing_type : hold_rising; - related_pin : "clk"; - rise_constraint(CONSTRAINT_TABLE) { - values("0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001"); - } - fall_constraint(CONSTRAINT_TABLE) { - values("0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001",\ - "0.001, 0.001, 0.001"); - } - } - } - - pin(clk){ - clock : true; - direction : input; - capacitance : 0.2091; - timing(){ - timing_type :"min_pulse_width"; - related_pin : clk; - rise_constraint(scalar) { - values("0.0"); - } - fall_constraint(scalar) { - values("0.0"); - } - } - timing(){ - timing_type :"minimum_period"; - related_pin : clk; - rise_constraint(scalar) { - values("0.0"); - } - fall_constraint(scalar) { - values("0.0"); - } - } - } - } -} diff --git a/compiler/tests/golden/sram_2_16_1_scn3me_subm.lef b/compiler/tests/golden/sram_2_16_1_scn3me_subm.lef index 5e8d62ab..7a2a54f2 100644 --- a/compiler/tests/golden/sram_2_16_1_scn3me_subm.lef +++ b/compiler/tests/golden/sram_2_16_1_scn3me_subm.lef @@ -7,11 +7,11 @@ UNITS END UNITS SITE MacroSite CLASS Core ; - SIZE 2250.0 by 1200.0 ; + SIZE 277800.0 by 440700.0 ; END MacroSite MACRO sram_2_16_1_scn3me_subm CLASS BLOCK ; - SIZE 2250.0 BY 1200.0 ; + SIZE 277800.0 BY 440700.0 ; SYMMETRY X Y R90 ; SITE MacroSite ; PIN DATA[0] @@ -577,14 +577,14 @@ MACRO sram_2_16_1_scn3me_subm RECT 127050.0 109650.0 122100.0 110550.0 ; RECT 130050.0 118350.0 105450.0 119250.0 ; RECT 127050.0 132150.0 102450.0 133050.0 ; - RECT 111450.0 93750.0 94500.0 94650.0 ; - RECT 108450.0 96450.0 97500.0 97350.0 ; - RECT 105450.0 111150.0 94500.0 112050.0 ; - RECT 108450.0 108450.0 97500.0 109350.0 ; - RECT 111450.0 121350.0 94500.0 122250.0 ; - RECT 102450.0 124050.0 97500.0 124950.0 ; - RECT 105450.0 138750.0 94500.0 139650.0 ; - RECT 102450.0 136050.0 97500.0 136950.0 ; + RECT 111450.0 96450.0 97500.0 97350.0 ; + RECT 108450.0 93750.0 94500.0 94650.0 ; + RECT 105450.0 108450.0 97500.0 109350.0 ; + RECT 108450.0 111150.0 94500.0 112050.0 ; + RECT 111450.0 124050.0 97500.0 124950.0 ; + RECT 102450.0 121350.0 94500.0 122250.0 ; + RECT 105450.0 136050.0 97500.0 136950.0 ; + RECT 102450.0 138750.0 94500.0 139650.0 ; RECT 88050.0 96450.0 87150.0 97350.0 ; RECT 88050.0 95250.0 87150.0 96150.0 ; RECT 92100.0 96450.0 87600.0 97350.0 ; @@ -865,14 +865,14 @@ MACRO sram_2_16_1_scn3me_subm RECT 104850.0 118200.0 106050.0 119400.0 ; RECT 126450.0 132000.0 127650.0 133200.0 ; RECT 101850.0 132000.0 103050.0 133200.0 ; - RECT 110850.0 93600.0 112050.0 94800.0 ; - RECT 107850.0 96300.0 109050.0 97500.0 ; - RECT 104850.0 111000.0 106050.0 112200.0 ; - RECT 107850.0 108300.0 109050.0 109500.0 ; - RECT 110850.0 121200.0 112050.0 122400.0 ; - RECT 101850.0 123900.0 103050.0 125100.0 ; - RECT 104850.0 138600.0 106050.0 139800.0 ; - RECT 101850.0 135900.0 103050.0 137100.0 ; + RECT 110850.0 96300.0 112050.0 97500.0 ; + RECT 107850.0 93600.0 109050.0 94800.0 ; + RECT 104850.0 108300.0 106050.0 109500.0 ; + RECT 107850.0 111000.0 109050.0 112200.0 ; + RECT 110850.0 123900.0 112050.0 125100.0 ; + RECT 101850.0 121200.0 103050.0 122400.0 ; + RECT 104850.0 135900.0 106050.0 137100.0 ; + RECT 101850.0 138600.0 103050.0 139800.0 ; RECT 79650.0 95250.0 75900.0 96150.0 ; RECT 79650.0 109650.0 75900.0 110550.0 ; RECT 79650.0 122850.0 75900.0 123750.0 ; @@ -896,14 +896,14 @@ MACRO sram_2_16_1_scn3me_subm RECT 127050.0 164850.0 122100.0 165750.0 ; RECT 130050.0 173550.0 105450.0 174450.0 ; RECT 127050.0 187350.0 102450.0 188250.0 ; - RECT 111450.0 148950.0 94500.0 149850.0 ; - RECT 108450.0 151650.0 97500.0 152550.0 ; - RECT 105450.0 166350.0 94500.0 167250.0 ; - RECT 108450.0 163650.0 97500.0 164550.0 ; - RECT 111450.0 176550.0 94500.0 177450.0 ; - RECT 102450.0 179250.0 97500.0 180150.0 ; - RECT 105450.0 193950.0 94500.0 194850.0 ; - RECT 102450.0 191250.0 97500.0 192150.0 ; + RECT 111450.0 151650.0 97500.0 152550.0 ; + RECT 108450.0 148950.0 94500.0 149850.0 ; + RECT 105450.0 163650.0 97500.0 164550.0 ; + RECT 108450.0 166350.0 94500.0 167250.0 ; + RECT 111450.0 179250.0 97500.0 180150.0 ; + RECT 102450.0 176550.0 94500.0 177450.0 ; + RECT 105450.0 191250.0 97500.0 192150.0 ; + RECT 102450.0 193950.0 94500.0 194850.0 ; RECT 88050.0 151650.0 87150.0 152550.0 ; RECT 88050.0 150450.0 87150.0 151350.0 ; RECT 92100.0 151650.0 87600.0 152550.0 ; @@ -1184,14 +1184,14 @@ MACRO sram_2_16_1_scn3me_subm RECT 104850.0 173400.0 106050.0 174600.0 ; RECT 126450.0 187200.0 127650.0 188400.0 ; RECT 101850.0 187200.0 103050.0 188400.0 ; - RECT 110850.0 148800.0 112050.0 150000.0 ; - RECT 107850.0 151500.0 109050.0 152700.0 ; - RECT 104850.0 166200.0 106050.0 167400.0 ; - RECT 107850.0 163500.0 109050.0 164700.0 ; - RECT 110850.0 176400.0 112050.0 177600.0 ; - RECT 101850.0 179100.0 103050.0 180300.0 ; - RECT 104850.0 193800.0 106050.0 195000.0 ; - RECT 101850.0 191100.0 103050.0 192300.0 ; + RECT 110850.0 151500.0 112050.0 152700.0 ; + RECT 107850.0 148800.0 109050.0 150000.0 ; + RECT 104850.0 163500.0 106050.0 164700.0 ; + RECT 107850.0 166200.0 109050.0 167400.0 ; + RECT 110850.0 179100.0 112050.0 180300.0 ; + RECT 101850.0 176400.0 103050.0 177600.0 ; + RECT 104850.0 191100.0 106050.0 192300.0 ; + RECT 101850.0 193800.0 103050.0 195000.0 ; RECT 79650.0 150450.0 75900.0 151350.0 ; RECT 79650.0 164850.0 75900.0 165750.0 ; RECT 79650.0 178050.0 75900.0 178950.0 ; @@ -4105,9 +4105,11 @@ MACRO sram_2_16_1_scn3me_subm RECT 16050.0 358350.0 15150.0 359250.0 ; RECT 8850.0 353400.0 7950.0 363000.0 ; RECT 22650.0 353400.0 21750.0 363000.0 ; - RECT 22650.0 396900.0 16800.0 397800.0 ; - RECT 22650.0 420300.0 16800.0 421200.0 ; - RECT 22200.0 427650.0 16800.0 428550.0 ; + RECT 22650.0 499050.0 21750.0 430200.0 ; + RECT 21750.0 397050.0 17400.0 397950.0 ; + RECT 21750.0 420450.0 17400.0 421350.0 ; + RECT 22650.0 371550.0 16800.0 372450.0 ; + RECT 16800.0 371550.0 6600.0 372450.0 ; RECT 4500.0 408600.0 16800.0 409500.0 ; RECT 4500.0 381000.0 16800.0 381900.0 ; RECT 29250.0 397800.0 28350.0 410400.0 ; @@ -4148,11 +4150,11 @@ MACRO sram_2_16_1_scn3me_subm RECT 32550.0 398400.0 33750.0 399600.0 ; RECT 32550.0 398400.0 33750.0 399600.0 ; RECT 32550.0 396000.0 33750.0 397200.0 ; - RECT 21750.0 430950.0 22650.0 431850.0 ; - RECT 49350.0 430950.0 50250.0 431850.0 ; - RECT 21750.0 429600.0 22650.0 431400.0 ; - RECT 22200.0 430950.0 49800.0 431850.0 ; - RECT 49350.0 429600.0 50250.0 431400.0 ; + RECT 21750.0 498150.0 22650.0 499050.0 ; + RECT 49350.0 498150.0 50250.0 499050.0 ; + RECT 21750.0 496800.0 22650.0 498600.0 ; + RECT 22200.0 498150.0 49800.0 499050.0 ; + RECT 49350.0 496800.0 50250.0 498600.0 ; RECT 37950.0 417000.0 36000.0 418200.0 ; RECT 49800.0 417000.0 47850.0 418200.0 ; RECT 48450.0 412200.0 50250.0 413400.0 ; @@ -4194,6 +4196,279 @@ MACRO sram_2_16_1_scn3me_subm RECT 36450.0 420000.0 35550.0 429600.0 ; RECT 50250.0 420000.0 49350.0 429600.0 ; RECT 42600.0 422400.0 43800.0 423600.0 ; + RECT 37950.0 436200.0 36000.0 437400.0 ; + RECT 49800.0 436200.0 47850.0 437400.0 ; + RECT 48450.0 431400.0 50250.0 432600.0 ; + RECT 39150.0 431400.0 35550.0 432600.0 ; + RECT 48450.0 434100.0 39150.0 435000.0 ; + RECT 39150.0 431400.0 37950.0 432600.0 ; + RECT 39150.0 433800.0 37950.0 435000.0 ; + RECT 39150.0 433800.0 37950.0 435000.0 ; + RECT 39150.0 431400.0 37950.0 432600.0 ; + RECT 48450.0 431400.0 47250.0 432600.0 ; + RECT 48450.0 433800.0 47250.0 435000.0 ; + RECT 48450.0 433800.0 47250.0 435000.0 ; + RECT 48450.0 431400.0 47250.0 432600.0 ; + RECT 38550.0 436200.0 37350.0 437400.0 ; + RECT 48450.0 436200.0 47250.0 437400.0 ; + RECT 43800.0 432000.0 42600.0 433200.0 ; + RECT 43800.0 432000.0 42600.0 433200.0 ; + RECT 43650.0 434550.0 42750.0 435450.0 ; + RECT 36450.0 429600.0 35550.0 439200.0 ; + RECT 50250.0 429600.0 49350.0 439200.0 ; + RECT 42600.0 432000.0 43800.0 433200.0 ; + RECT 37950.0 445800.0 36000.0 447000.0 ; + RECT 49800.0 445800.0 47850.0 447000.0 ; + RECT 48450.0 441000.0 50250.0 442200.0 ; + RECT 39150.0 441000.0 35550.0 442200.0 ; + RECT 48450.0 443700.0 39150.0 444600.0 ; + RECT 39150.0 441000.0 37950.0 442200.0 ; + RECT 39150.0 443400.0 37950.0 444600.0 ; + RECT 39150.0 443400.0 37950.0 444600.0 ; + RECT 39150.0 441000.0 37950.0 442200.0 ; + RECT 48450.0 441000.0 47250.0 442200.0 ; + RECT 48450.0 443400.0 47250.0 444600.0 ; + RECT 48450.0 443400.0 47250.0 444600.0 ; + RECT 48450.0 441000.0 47250.0 442200.0 ; + RECT 38550.0 445800.0 37350.0 447000.0 ; + RECT 48450.0 445800.0 47250.0 447000.0 ; + RECT 43800.0 441600.0 42600.0 442800.0 ; + RECT 43800.0 441600.0 42600.0 442800.0 ; + RECT 43650.0 444150.0 42750.0 445050.0 ; + RECT 36450.0 439200.0 35550.0 448800.0 ; + RECT 50250.0 439200.0 49350.0 448800.0 ; + RECT 42600.0 441600.0 43800.0 442800.0 ; + RECT 37950.0 455400.0 36000.0 456600.0 ; + RECT 49800.0 455400.0 47850.0 456600.0 ; + RECT 48450.0 450600.0 50250.0 451800.0 ; + RECT 39150.0 450600.0 35550.0 451800.0 ; + RECT 48450.0 453300.0 39150.0 454200.0 ; + RECT 39150.0 450600.0 37950.0 451800.0 ; + RECT 39150.0 453000.0 37950.0 454200.0 ; + RECT 39150.0 453000.0 37950.0 454200.0 ; + RECT 39150.0 450600.0 37950.0 451800.0 ; + RECT 48450.0 450600.0 47250.0 451800.0 ; + RECT 48450.0 453000.0 47250.0 454200.0 ; + RECT 48450.0 453000.0 47250.0 454200.0 ; + RECT 48450.0 450600.0 47250.0 451800.0 ; + RECT 38550.0 455400.0 37350.0 456600.0 ; + RECT 48450.0 455400.0 47250.0 456600.0 ; + RECT 43800.0 451200.0 42600.0 452400.0 ; + RECT 43800.0 451200.0 42600.0 452400.0 ; + RECT 43650.0 453750.0 42750.0 454650.0 ; + RECT 36450.0 448800.0 35550.0 458400.0 ; + RECT 50250.0 448800.0 49350.0 458400.0 ; + RECT 42600.0 451200.0 43800.0 452400.0 ; + RECT 37950.0 465000.0 36000.0 466200.0 ; + RECT 49800.0 465000.0 47850.0 466200.0 ; + RECT 48450.0 460200.0 50250.0 461400.0 ; + RECT 39150.0 460200.0 35550.0 461400.0 ; + RECT 48450.0 462900.0 39150.0 463800.0 ; + RECT 39150.0 460200.0 37950.0 461400.0 ; + RECT 39150.0 462600.0 37950.0 463800.0 ; + RECT 39150.0 462600.0 37950.0 463800.0 ; + RECT 39150.0 460200.0 37950.0 461400.0 ; + RECT 48450.0 460200.0 47250.0 461400.0 ; + RECT 48450.0 462600.0 47250.0 463800.0 ; + RECT 48450.0 462600.0 47250.0 463800.0 ; + RECT 48450.0 460200.0 47250.0 461400.0 ; + RECT 38550.0 465000.0 37350.0 466200.0 ; + RECT 48450.0 465000.0 47250.0 466200.0 ; + RECT 43800.0 460800.0 42600.0 462000.0 ; + RECT 43800.0 460800.0 42600.0 462000.0 ; + RECT 43650.0 463350.0 42750.0 464250.0 ; + RECT 36450.0 458400.0 35550.0 468000.0 ; + RECT 50250.0 458400.0 49350.0 468000.0 ; + RECT 42600.0 460800.0 43800.0 462000.0 ; + RECT 37950.0 474600.0 36000.0 475800.0 ; + RECT 49800.0 474600.0 47850.0 475800.0 ; + RECT 48450.0 469800.0 50250.0 471000.0 ; + RECT 39150.0 469800.0 35550.0 471000.0 ; + RECT 48450.0 472500.0 39150.0 473400.0 ; + RECT 39150.0 469800.0 37950.0 471000.0 ; + RECT 39150.0 472200.0 37950.0 473400.0 ; + RECT 39150.0 472200.0 37950.0 473400.0 ; + RECT 39150.0 469800.0 37950.0 471000.0 ; + RECT 48450.0 469800.0 47250.0 471000.0 ; + RECT 48450.0 472200.0 47250.0 473400.0 ; + RECT 48450.0 472200.0 47250.0 473400.0 ; + RECT 48450.0 469800.0 47250.0 471000.0 ; + RECT 38550.0 474600.0 37350.0 475800.0 ; + RECT 48450.0 474600.0 47250.0 475800.0 ; + RECT 43800.0 470400.0 42600.0 471600.0 ; + RECT 43800.0 470400.0 42600.0 471600.0 ; + RECT 43650.0 472950.0 42750.0 473850.0 ; + RECT 36450.0 468000.0 35550.0 477600.0 ; + RECT 50250.0 468000.0 49350.0 477600.0 ; + RECT 42600.0 470400.0 43800.0 471600.0 ; + RECT 37950.0 484200.0 36000.0 485400.0 ; + RECT 49800.0 484200.0 47850.0 485400.0 ; + RECT 48450.0 479400.0 50250.0 480600.0 ; + RECT 39150.0 479400.0 35550.0 480600.0 ; + RECT 48450.0 482100.0 39150.0 483000.0 ; + RECT 39150.0 479400.0 37950.0 480600.0 ; + RECT 39150.0 481800.0 37950.0 483000.0 ; + RECT 39150.0 481800.0 37950.0 483000.0 ; + RECT 39150.0 479400.0 37950.0 480600.0 ; + RECT 48450.0 479400.0 47250.0 480600.0 ; + RECT 48450.0 481800.0 47250.0 483000.0 ; + RECT 48450.0 481800.0 47250.0 483000.0 ; + RECT 48450.0 479400.0 47250.0 480600.0 ; + RECT 38550.0 484200.0 37350.0 485400.0 ; + RECT 48450.0 484200.0 47250.0 485400.0 ; + RECT 43800.0 480000.0 42600.0 481200.0 ; + RECT 43800.0 480000.0 42600.0 481200.0 ; + RECT 43650.0 482550.0 42750.0 483450.0 ; + RECT 36450.0 477600.0 35550.0 487200.0 ; + RECT 50250.0 477600.0 49350.0 487200.0 ; + RECT 42600.0 480000.0 43800.0 481200.0 ; + RECT 37950.0 493800.0 36000.0 495000.0 ; + RECT 49800.0 493800.0 47850.0 495000.0 ; + RECT 48450.0 489000.0 50250.0 490200.0 ; + RECT 39150.0 489000.0 35550.0 490200.0 ; + RECT 48450.0 491700.0 39150.0 492600.0 ; + RECT 39150.0 489000.0 37950.0 490200.0 ; + RECT 39150.0 491400.0 37950.0 492600.0 ; + RECT 39150.0 491400.0 37950.0 492600.0 ; + RECT 39150.0 489000.0 37950.0 490200.0 ; + RECT 48450.0 489000.0 47250.0 490200.0 ; + RECT 48450.0 491400.0 47250.0 492600.0 ; + RECT 48450.0 491400.0 47250.0 492600.0 ; + RECT 48450.0 489000.0 47250.0 490200.0 ; + RECT 38550.0 493800.0 37350.0 495000.0 ; + RECT 48450.0 493800.0 47250.0 495000.0 ; + RECT 43800.0 489600.0 42600.0 490800.0 ; + RECT 43800.0 489600.0 42600.0 490800.0 ; + RECT 43650.0 492150.0 42750.0 493050.0 ; + RECT 36450.0 487200.0 35550.0 496800.0 ; + RECT 50250.0 487200.0 49350.0 496800.0 ; + RECT 42600.0 489600.0 43800.0 490800.0 ; + RECT 34050.0 480600.0 36000.0 479400.0 ; + RECT 22200.0 480600.0 24150.0 479400.0 ; + RECT 23550.0 485400.0 21750.0 484200.0 ; + RECT 32850.0 485400.0 36450.0 484200.0 ; + RECT 23550.0 482700.0 32850.0 481800.0 ; + RECT 32850.0 485400.0 34050.0 484200.0 ; + RECT 32850.0 483000.0 34050.0 481800.0 ; + RECT 32850.0 483000.0 34050.0 481800.0 ; + RECT 32850.0 485400.0 34050.0 484200.0 ; + RECT 23550.0 485400.0 24750.0 484200.0 ; + RECT 23550.0 483000.0 24750.0 481800.0 ; + RECT 23550.0 483000.0 24750.0 481800.0 ; + RECT 23550.0 485400.0 24750.0 484200.0 ; + RECT 33450.0 480600.0 34650.0 479400.0 ; + RECT 23550.0 480600.0 24750.0 479400.0 ; + RECT 28200.0 484800.0 29400.0 483600.0 ; + RECT 28200.0 484800.0 29400.0 483600.0 ; + RECT 28350.0 482250.0 29250.0 481350.0 ; + RECT 35550.0 487200.0 36450.0 477600.0 ; + RECT 21750.0 487200.0 22650.0 477600.0 ; + RECT 28200.0 483600.0 29400.0 484800.0 ; + RECT 34050.0 471000.0 36000.0 469800.0 ; + RECT 22200.0 471000.0 24150.0 469800.0 ; + RECT 23550.0 475800.0 21750.0 474600.0 ; + RECT 32850.0 475800.0 36450.0 474600.0 ; + RECT 23550.0 473100.0 32850.0 472200.0 ; + RECT 32850.0 475800.0 34050.0 474600.0 ; + RECT 32850.0 473400.0 34050.0 472200.0 ; + RECT 32850.0 473400.0 34050.0 472200.0 ; + RECT 32850.0 475800.0 34050.0 474600.0 ; + RECT 23550.0 475800.0 24750.0 474600.0 ; + RECT 23550.0 473400.0 24750.0 472200.0 ; + RECT 23550.0 473400.0 24750.0 472200.0 ; + RECT 23550.0 475800.0 24750.0 474600.0 ; + RECT 33450.0 471000.0 34650.0 469800.0 ; + RECT 23550.0 471000.0 24750.0 469800.0 ; + RECT 28200.0 475200.0 29400.0 474000.0 ; + RECT 28200.0 475200.0 29400.0 474000.0 ; + RECT 28350.0 472650.0 29250.0 471750.0 ; + RECT 35550.0 477600.0 36450.0 468000.0 ; + RECT 21750.0 477600.0 22650.0 468000.0 ; + RECT 28200.0 474000.0 29400.0 475200.0 ; + RECT 34050.0 461400.0 36000.0 460200.0 ; + RECT 22200.0 461400.0 24150.0 460200.0 ; + RECT 23550.0 466200.0 21750.0 465000.0 ; + RECT 32850.0 466200.0 36450.0 465000.0 ; + RECT 23550.0 463500.0 32850.0 462600.0 ; + RECT 32850.0 466200.0 34050.0 465000.0 ; + RECT 32850.0 463800.0 34050.0 462600.0 ; + RECT 32850.0 463800.0 34050.0 462600.0 ; + RECT 32850.0 466200.0 34050.0 465000.0 ; + RECT 23550.0 466200.0 24750.0 465000.0 ; + RECT 23550.0 463800.0 24750.0 462600.0 ; + RECT 23550.0 463800.0 24750.0 462600.0 ; + RECT 23550.0 466200.0 24750.0 465000.0 ; + RECT 33450.0 461400.0 34650.0 460200.0 ; + RECT 23550.0 461400.0 24750.0 460200.0 ; + RECT 28200.0 465600.0 29400.0 464400.0 ; + RECT 28200.0 465600.0 29400.0 464400.0 ; + RECT 28350.0 463050.0 29250.0 462150.0 ; + RECT 35550.0 468000.0 36450.0 458400.0 ; + RECT 21750.0 468000.0 22650.0 458400.0 ; + RECT 28200.0 464400.0 29400.0 465600.0 ; + RECT 34050.0 451800.0 36000.0 450600.0 ; + RECT 22200.0 451800.0 24150.0 450600.0 ; + RECT 23550.0 456600.0 21750.0 455400.0 ; + RECT 32850.0 456600.0 36450.0 455400.0 ; + RECT 23550.0 453900.0 32850.0 453000.0 ; + RECT 32850.0 456600.0 34050.0 455400.0 ; + RECT 32850.0 454200.0 34050.0 453000.0 ; + RECT 32850.0 454200.0 34050.0 453000.0 ; + RECT 32850.0 456600.0 34050.0 455400.0 ; + RECT 23550.0 456600.0 24750.0 455400.0 ; + RECT 23550.0 454200.0 24750.0 453000.0 ; + RECT 23550.0 454200.0 24750.0 453000.0 ; + RECT 23550.0 456600.0 24750.0 455400.0 ; + RECT 33450.0 451800.0 34650.0 450600.0 ; + RECT 23550.0 451800.0 24750.0 450600.0 ; + RECT 28200.0 456000.0 29400.0 454800.0 ; + RECT 28200.0 456000.0 29400.0 454800.0 ; + RECT 28350.0 453450.0 29250.0 452550.0 ; + RECT 35550.0 458400.0 36450.0 448800.0 ; + RECT 21750.0 458400.0 22650.0 448800.0 ; + RECT 28200.0 454800.0 29400.0 456000.0 ; + RECT 34050.0 442200.0 36000.0 441000.0 ; + RECT 22200.0 442200.0 24150.0 441000.0 ; + RECT 23550.0 447000.0 21750.0 445800.0 ; + RECT 32850.0 447000.0 36450.0 445800.0 ; + RECT 23550.0 444300.0 32850.0 443400.0 ; + RECT 32850.0 447000.0 34050.0 445800.0 ; + RECT 32850.0 444600.0 34050.0 443400.0 ; + RECT 32850.0 444600.0 34050.0 443400.0 ; + RECT 32850.0 447000.0 34050.0 445800.0 ; + RECT 23550.0 447000.0 24750.0 445800.0 ; + RECT 23550.0 444600.0 24750.0 443400.0 ; + RECT 23550.0 444600.0 24750.0 443400.0 ; + RECT 23550.0 447000.0 24750.0 445800.0 ; + RECT 33450.0 442200.0 34650.0 441000.0 ; + RECT 23550.0 442200.0 24750.0 441000.0 ; + RECT 28200.0 446400.0 29400.0 445200.0 ; + RECT 28200.0 446400.0 29400.0 445200.0 ; + RECT 28350.0 443850.0 29250.0 442950.0 ; + RECT 35550.0 448800.0 36450.0 439200.0 ; + RECT 21750.0 448800.0 22650.0 439200.0 ; + RECT 28200.0 445200.0 29400.0 446400.0 ; + RECT 34050.0 432600.0 36000.0 431400.0 ; + RECT 22200.0 432600.0 24150.0 431400.0 ; + RECT 23550.0 437400.0 21750.0 436200.0 ; + RECT 32850.0 437400.0 36450.0 436200.0 ; + RECT 23550.0 434700.0 32850.0 433800.0 ; + RECT 32850.0 437400.0 34050.0 436200.0 ; + RECT 32850.0 435000.0 34050.0 433800.0 ; + RECT 32850.0 435000.0 34050.0 433800.0 ; + RECT 32850.0 437400.0 34050.0 436200.0 ; + RECT 23550.0 437400.0 24750.0 436200.0 ; + RECT 23550.0 435000.0 24750.0 433800.0 ; + RECT 23550.0 435000.0 24750.0 433800.0 ; + RECT 23550.0 437400.0 24750.0 436200.0 ; + RECT 33450.0 432600.0 34650.0 431400.0 ; + RECT 23550.0 432600.0 24750.0 431400.0 ; + RECT 28200.0 436800.0 29400.0 435600.0 ; + RECT 28200.0 436800.0 29400.0 435600.0 ; + RECT 28350.0 434250.0 29250.0 433350.0 ; + RECT 35550.0 439200.0 36450.0 429600.0 ; + RECT 21750.0 439200.0 22650.0 429600.0 ; + RECT 28200.0 435600.0 29400.0 436800.0 ; RECT 34050.0 423000.0 36000.0 421800.0 ; RECT 22200.0 423000.0 24150.0 421800.0 ; RECT 23550.0 427800.0 21750.0 426600.0 ; @@ -4237,25 +4512,26 @@ MACRO sram_2_16_1_scn3me_subm RECT 21750.0 420000.0 22650.0 410400.0 ; RECT 28200.0 416400.0 29400.0 417600.0 ; RECT 42600.0 415200.0 43800.0 416400.0 ; - RECT 42600.0 424800.0 43800.0 426000.0 ; - RECT 28200.0 423600.0 29400.0 424800.0 ; + RECT 42600.0 453600.0 43800.0 454800.0 ; + RECT 42600.0 492000.0 43800.0 493200.0 ; + RECT 28200.0 452400.0 29400.0 453600.0 ; RECT 42600.0 412800.0 43800.0 414000.0 ; RECT 28350.0 410400.0 29250.0 414150.0 ; - RECT 35550.0 410400.0 36450.0 429600.0 ; - RECT 21750.0 410400.0 22650.0 429600.0 ; - RECT 49350.0 410400.0 50250.0 429600.0 ; + RECT 35550.0 410400.0 36450.0 496800.0 ; + RECT 21750.0 410400.0 22650.0 496800.0 ; + RECT 49350.0 410400.0 50250.0 496800.0 ; RECT 16800.0 395400.0 6600.0 381600.0 ; RECT 16800.0 395400.0 6600.0 409200.0 ; RECT 16800.0 423000.0 6600.0 409200.0 ; RECT 17400.0 396900.0 6000.0 398100.0 ; RECT 17400.0 420300.0 6000.0 421500.0 ; RECT 17400.0 408600.0 6000.0 409500.0 ; - RECT 22650.0 396900.0 21450.0 398100.0 ; - RECT 22650.0 420300.0 21450.0 421500.0 ; - RECT 22650.0 410400.0 21450.0 411600.0 ; - RECT 22650.0 370800.0 21450.0 372000.0 ; - RECT 21600.0 427500.0 22800.0 428700.0 ; - RECT 16200.0 427500.0 17400.0 428700.0 ; + RECT 22350.0 396900.0 21150.0 398100.0 ; + RECT 22350.0 420300.0 21150.0 421500.0 ; + RECT 22200.0 410400.0 21000.0 411600.0 ; + RECT 22800.0 370800.0 21600.0 372000.0 ; + RECT 16200.0 371400.0 17400.0 372600.0 ; + RECT 6000.0 371400.0 7200.0 372600.0 ; RECT 29400.0 397200.0 28200.0 398400.0 ; RECT 19350.0 383700.0 20550.0 384900.0 ; RECT 19350.0 375600.0 20550.0 376800.0 ; @@ -4264,7 +4540,7 @@ MACRO sram_2_16_1_scn3me_subm RECT 29250.0 362400.0 28350.0 375750.0 ; RECT 4500.0 362400.0 3600.0 425250.0 ; RECT 36450.0 362400.0 35550.0 410400.0 ; - RECT 22650.0 362400.0 21750.0 381600.0 ; + RECT 22650.0 362400.0 21750.0 372000.0 ; RECT 50250.0 362400.0 49350.0 410400.0 ; RECT 43950.0 285750.0 42750.0 284550.0 ; RECT 43950.0 244800.0 42750.0 243600.0 ; @@ -4461,14 +4737,14 @@ MACRO sram_2_16_1_scn3me_subm RECT 104850.0 118200.0 106050.0 119400.0 ; RECT 126450.0 132000.0 127650.0 133200.0 ; RECT 101850.0 132000.0 103050.0 133200.0 ; - RECT 110850.0 93600.0 112050.0 94800.0 ; - RECT 107850.0 96300.0 109050.0 97500.0 ; - RECT 104850.0 111000.0 106050.0 112200.0 ; - RECT 107850.0 108300.0 109050.0 109500.0 ; - RECT 110850.0 121200.0 112050.0 122400.0 ; - RECT 101850.0 123900.0 103050.0 125100.0 ; - RECT 104850.0 138600.0 106050.0 139800.0 ; - RECT 101850.0 135900.0 103050.0 137100.0 ; + RECT 110850.0 96300.0 112050.0 97500.0 ; + RECT 107850.0 93600.0 109050.0 94800.0 ; + RECT 104850.0 108300.0 106050.0 109500.0 ; + RECT 107850.0 111000.0 109050.0 112200.0 ; + RECT 110850.0 123900.0 112050.0 125100.0 ; + RECT 101850.0 121200.0 103050.0 122400.0 ; + RECT 104850.0 135900.0 106050.0 137100.0 ; + RECT 101850.0 138600.0 103050.0 139800.0 ; RECT 130500.0 89100.0 129600.0 142500.0 ; RECT 127500.0 89100.0 126600.0 142500.0 ; RECT 105900.0 144300.0 105000.0 197700.0 ; @@ -4515,14 +4791,14 @@ MACRO sram_2_16_1_scn3me_subm RECT 104850.0 173400.0 106050.0 174600.0 ; RECT 126450.0 187200.0 127650.0 188400.0 ; RECT 101850.0 187200.0 103050.0 188400.0 ; - RECT 110850.0 148800.0 112050.0 150000.0 ; - RECT 107850.0 151500.0 109050.0 152700.0 ; - RECT 104850.0 166200.0 106050.0 167400.0 ; - RECT 107850.0 163500.0 109050.0 164700.0 ; - RECT 110850.0 176400.0 112050.0 177600.0 ; - RECT 101850.0 179100.0 103050.0 180300.0 ; - RECT 104850.0 193800.0 106050.0 195000.0 ; - RECT 101850.0 191100.0 103050.0 192300.0 ; + RECT 110850.0 151500.0 112050.0 152700.0 ; + RECT 107850.0 148800.0 109050.0 150000.0 ; + RECT 104850.0 163500.0 106050.0 164700.0 ; + RECT 107850.0 166200.0 109050.0 167400.0 ; + RECT 110850.0 179100.0 112050.0 180300.0 ; + RECT 101850.0 176400.0 103050.0 177600.0 ; + RECT 104850.0 191100.0 106050.0 192300.0 ; + RECT 101850.0 193800.0 103050.0 195000.0 ; RECT 130500.0 144300.0 129600.0 197700.0 ; RECT 127500.0 144300.0 126600.0 197700.0 ; RECT 80250.0 206850.0 81150.0 207750.0 ; @@ -5006,6 +5282,7 @@ MACRO sram_2_16_1_scn3me_subm RECT 49800.0 292800.0 1.42108547152e-11 293700.0 ; RECT 49800.0 295500.0 1.42108547152e-11 296400.0 ; RECT 49800.0 300900.0 1.42108547152e-11 301800.0 ; + RECT 43350.0 243750.0 36000.0 244650.0 ; RECT 33750.0 205350.0 32850.0 285150.0 ; RECT 49800.0 287400.0 47100.0 288300.0 ; RECT 38700.0 298200.0 36000.0 299100.0 ; @@ -5071,25 +5348,51 @@ MACRO sram_2_16_1_scn3me_subm RECT 10800.0 288450.0 9600.0 287250.0 ; RECT 31200.0 263100.0 30000.0 261900.0 ; RECT 31200.0 288450.0 30000.0 287250.0 ; - RECT 22650.0 372000.0 21750.0 427500.0 ; - RECT 22650.0 381600.0 21750.0 384300.0 ; - RECT 22650.0 384300.0 21750.0 428100.0 ; - RECT 17250.0 425400.0 16350.0 428100.0 ; + RECT 22650.0 372000.0 21750.0 430200.0 ; + RECT 17250.0 372000.0 16350.0 425400.0 ; + RECT 7050.0 372000.0 6150.0 425400.0 ; RECT 20400.0 376200.0 19500.0 384300.0 ; RECT 13650.0 376200.0 12750.0 381000.0 ; RECT 42750.0 415800.0 43650.0 423000.0 ; - RECT 35550.0 424950.0 36450.0 425850.0 ; - RECT 35550.0 426150.0 36450.0 427050.0 ; - RECT 36000.0 424950.0 43200.0 425850.0 ; - RECT 35550.0 425400.0 36450.0 426600.0 ; - RECT 28800.0 426150.0 36000.0 427050.0 ; - RECT 28350.0 417000.0 29250.0 424200.0 ; + RECT 42750.0 423000.0 43650.0 432600.0 ; + RECT 42750.0 432600.0 43650.0 442200.0 ; + RECT 42750.0 442200.0 43650.0 451800.0 ; + RECT 42750.0 454200.0 43650.0 461400.0 ; + RECT 42750.0 461400.0 43650.0 471000.0 ; + RECT 42750.0 471000.0 43650.0 480600.0 ; + RECT 42750.0 480600.0 43650.0 490200.0 ; + RECT 35550.0 492150.0 36450.0 493050.0 ; + RECT 35550.0 483750.0 36450.0 484650.0 ; + RECT 36000.0 492150.0 43200.0 493050.0 ; + RECT 35550.0 484200.0 36450.0 492600.0 ; + RECT 28800.0 483750.0 36000.0 484650.0 ; + RECT 28350.0 474600.0 29250.0 484200.0 ; + RECT 28350.0 465000.0 29250.0 474600.0 ; + RECT 28350.0 455400.0 29250.0 465000.0 ; + RECT 28350.0 445800.0 29250.0 453000.0 ; + RECT 28350.0 436200.0 29250.0 445800.0 ; + RECT 28350.0 426600.0 29250.0 436200.0 ; + RECT 28350.0 417000.0 29250.0 426600.0 ; RECT 42600.0 422400.0 43800.0 423600.0 ; + RECT 42600.0 432000.0 43800.0 433200.0 ; + RECT 42600.0 441600.0 43800.0 442800.0 ; + RECT 42600.0 451200.0 43800.0 452400.0 ; + RECT 42600.0 460800.0 43800.0 462000.0 ; + RECT 42600.0 470400.0 43800.0 471600.0 ; + RECT 42600.0 480000.0 43800.0 481200.0 ; + RECT 42600.0 489600.0 43800.0 490800.0 ; + RECT 28200.0 483600.0 29400.0 484800.0 ; + RECT 28200.0 474000.0 29400.0 475200.0 ; + RECT 28200.0 464400.0 29400.0 465600.0 ; + RECT 28200.0 454800.0 29400.0 456000.0 ; + RECT 28200.0 445200.0 29400.0 446400.0 ; + RECT 28200.0 435600.0 29400.0 436800.0 ; RECT 28200.0 426000.0 29400.0 427200.0 ; RECT 28200.0 416400.0 29400.0 417600.0 ; RECT 42600.0 415200.0 43800.0 416400.0 ; - RECT 42600.0 424800.0 43800.0 426000.0 ; - RECT 28200.0 423600.0 29400.0 424800.0 ; + RECT 42600.0 453600.0 43800.0 454800.0 ; + RECT 42600.0 492000.0 43800.0 493200.0 ; + RECT 28200.0 452400.0 29400.0 453600.0 ; RECT 16800.0 395400.0 6600.0 381600.0 ; RECT 16800.0 395400.0 6600.0 409200.0 ; RECT 16800.0 423000.0 6600.0 409200.0 ; @@ -5097,19 +5400,19 @@ MACRO sram_2_16_1_scn3me_subm RECT 10800.0 394800.0 9600.0 425400.0 ; RECT 17400.0 394800.0 16200.0 425400.0 ; RECT 7200.0 394800.0 6000.0 425400.0 ; - RECT 22650.0 396900.0 21450.0 398100.0 ; - RECT 22650.0 420300.0 21450.0 421500.0 ; - RECT 22650.0 410400.0 21450.0 411600.0 ; - RECT 22650.0 370800.0 21450.0 372000.0 ; - RECT 21600.0 427500.0 22800.0 428700.0 ; - RECT 16200.0 427500.0 17400.0 428700.0 ; + RECT 22350.0 396900.0 21150.0 398100.0 ; + RECT 22350.0 420300.0 21150.0 421500.0 ; + RECT 22200.0 410400.0 21000.0 411600.0 ; + RECT 22800.0 370800.0 21600.0 372000.0 ; + RECT 16200.0 371400.0 17400.0 372600.0 ; + RECT 6000.0 371400.0 7200.0 372600.0 ; RECT 19350.0 383700.0 20550.0 384900.0 ; RECT 19350.0 375600.0 20550.0 376800.0 ; RECT 12600.0 375600.0 13800.0 376800.0 ; RECT 43950.0 285750.0 42750.0 284550.0 ; RECT 43950.0 244800.0 42750.0 243600.0 ; - RECT 43950.0 304650.0 42750.0 303450.0 ; - RECT 43950.0 244800.0 42750.0 243600.0 ; + RECT 36600.0 244800.0 35400.0 243600.0 ; + RECT 36600.0 304650.0 35400.0 303450.0 ; RECT 33900.0 205950.0 32700.0 204750.0 ; RECT 29850.0 285750.0 28650.0 284550.0 ; RECT 27150.0 291150.0 25950.0 289950.0 ; @@ -5202,7 +5505,7 @@ MACRO sram_2_16_1_scn3me_subm RECT 23550.0 262500.0 22050.0 295950.0 ; RECT 10950.0 262500.0 9450.0 287850.0 ; RECT 31350.0 262500.0 29850.0 287850.0 ; - RECT 44100.0 244200.0 42600.0 304050.0 ; + RECT 36750.0 244200.0 35250.0 304050.0 ; RECT 30750.0 304050.0 29250.0 327900.0 ; RECT 28050.0 301350.0 26550.0 330900.0 ; RECT 4200.0 203400.0 6000.0 205200.0 ; @@ -5220,8 +5523,8 @@ MACRO sram_2_16_1_scn3me_subm RECT 11100.0 288750.0 9300.0 286950.0 ; RECT 31500.0 263400.0 29700.0 261600.0 ; RECT 31500.0 288750.0 29700.0 286950.0 ; - RECT 44250.0 245100.0 42450.0 243300.0 ; - RECT 44250.0 304950.0 42450.0 303150.0 ; + RECT 36900.0 245100.0 35100.0 243300.0 ; + RECT 36900.0 304950.0 35100.0 303150.0 ; RECT 30900.0 328800.0 29100.0 327000.0 ; RECT 30900.0 304950.0 29100.0 303150.0 ; RECT 28200.0 331800.0 26400.0 330000.0 ; diff --git a/compiler/tests/golden/sram_2_16_1_scn3me_subm.lib b/compiler/tests/golden/sram_2_16_1_scn3me_subm_TT_50V_25C.lib similarity index 63% rename from compiler/tests/golden/sram_2_16_1_scn3me_subm.lib rename to compiler/tests/golden/sram_2_16_1_scn3me_subm_TT_50V_25C.lib index 5a8ebfc6..b6fc4525 100644 --- a/compiler/tests/golden/sram_2_16_1_scn3me_subm.lib +++ b/compiler/tests/golden/sram_2_16_1_scn3me_subm_TT_50V_25C.lib @@ -1,4 +1,4 @@ -library (sram_2_16_1_scn3me_subm_lib){ +library (sram_2_16_1_scn3me_subm_TT_50V_25C_lib){ delay_model : "table_lookup"; time_unit : "1ns" ; voltage_unit : "1v" ; @@ -9,7 +9,7 @@ library (sram_2_16_1_scn3me_subm_lib){ pulling_resistance_unit :"1kohm" ; operating_conditions(TT){ voltage : 5.0 ; - temperature : 25.000 ; + temperature : 25; } input_threshold_pct_fall : 50.0 ; @@ -74,7 +74,7 @@ cell (sram_2_16_1_scn3me_subm){ dont_use : true; map_only : true; dont_touch : true; - area : 2.7; + area : 122426.46; bus(DATA){ bus_type : DATA; @@ -92,47 +92,47 @@ cell (sram_2_16_1_scn3me_subm){ internal_power(){ when : "OEb & !clk"; rise_power(scalar){ - values("3.2612"); + values("11.756062"); } fall_power(scalar){ - values("3.5985"); + values("7.1840422"); } } timing(){ timing_type : setup_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.082, 0.088, 0.186",\ - "0.082, 0.088, 0.186",\ - "0.082, 0.088, 0.186"); + values("0.076, 0.076, 0.149",\ + "0.076, 0.076, 0.149",\ + "0.076, 0.076, 0.149"); } fall_constraint(CONSTRAINT_TABLE) { - values("0.021, 0.021, 0.027",\ - "0.021, 0.021, 0.027",\ - "0.021, 0.021, 0.027"); + values("0.039, 0.039, 0.027",\ + "0.039, 0.039, 0.027",\ + "0.039, 0.039, 0.027"); } } timing(){ timing_type : hold_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.015, 0.021",\ - "0.009, 0.015, 0.021",\ - "0.009, 0.015, 0.021"); + values("-0.004, -0.004, 0.009",\ + "-0.004, -0.004, 0.009",\ + "-0.004, -0.004, 0.009"); } fall_constraint(CONSTRAINT_TABLE) { - values("-0.065, -0.071, -0.175",\ - "-0.065, -0.071, -0.175",\ - "-0.065, -0.071, -0.175"); + values("-0.052, -0.059, -0.132",\ + "-0.052, -0.059, -0.132",\ + "-0.052, -0.059, -0.132"); } } internal_power(){ when : "!OEb & !clk"; rise_power(scalar){ - values("5.1597"); + values("10.730552"); } fall_power(scalar){ - values("5.1863"); + values("10.584523"); } } timing(){ @@ -140,24 +140,24 @@ cell (sram_2_16_1_scn3me_subm){ related_pin : "clk"; timing_type : falling_edge; cell_rise(CELL_TABLE) { - values("0.509, 0.592, 1.265",\ - "0.512, 0.595, 1.271",\ - "0.561, 0.642, 1.317"); + values("0.458, 0.503, 0.87",\ + "0.461, 0.505, 0.873",\ + "0.5, 0.544, 0.911"); } cell_fall(CELL_TABLE) { - values("1.449, 1.549, 2.511",\ - "1.453, 1.555, 2.518",\ - "1.505, 1.607, 2.568"); + values("0.573, 0.649, 1.249",\ + "0.576, 0.651, 1.252",\ + "0.616, 0.69, 1.289"); } rise_transition(CELL_TABLE) { - values("0.19, 0.335, 1.887",\ - "0.192, 0.336, 1.886",\ - "0.194, 0.339, 1.886"); + values("0.153, 0.232, 1.084",\ + "0.153, 0.233, 1.084",\ + "0.156, 0.236, 1.084"); } fall_transition(CELL_TABLE) { - values("0.282, 0.465, 2.464",\ - "0.283, 0.466, 2.463",\ - "0.283, 0.465, 2.455"); + values("0.277, 0.355, 1.499",\ + "0.277, 0.357, 1.499",\ + "0.278, 0.362, 1.499"); } } } @@ -174,28 +174,28 @@ cell (sram_2_16_1_scn3me_subm){ timing_type : setup_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.082, 0.088, 0.186",\ - "0.082, 0.088, 0.186",\ - "0.082, 0.088, 0.186"); + values("0.076, 0.076, 0.149",\ + "0.076, 0.076, 0.149",\ + "0.076, 0.076, 0.149"); } fall_constraint(CONSTRAINT_TABLE) { - values("0.021, 0.021, 0.027",\ - "0.021, 0.021, 0.027",\ - "0.021, 0.021, 0.027"); + values("0.039, 0.039, 0.027",\ + "0.039, 0.039, 0.027",\ + "0.039, 0.039, 0.027"); } } timing(){ timing_type : hold_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.015, 0.021",\ - "0.009, 0.015, 0.021",\ - "0.009, 0.015, 0.021"); + values("-0.004, -0.004, 0.009",\ + "-0.004, -0.004, 0.009",\ + "-0.004, -0.004, 0.009"); } fall_constraint(CONSTRAINT_TABLE) { - values("-0.065, -0.071, -0.175",\ - "-0.065, -0.071, -0.175",\ - "-0.065, -0.071, -0.175"); + values("-0.052, -0.059, -0.132",\ + "-0.052, -0.059, -0.132",\ + "-0.052, -0.059, -0.132"); } } } @@ -208,28 +208,28 @@ cell (sram_2_16_1_scn3me_subm){ timing_type : setup_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.082, 0.088, 0.186",\ - "0.082, 0.088, 0.186",\ - "0.082, 0.088, 0.186"); + values("0.076, 0.076, 0.149",\ + "0.076, 0.076, 0.149",\ + "0.076, 0.076, 0.149"); } fall_constraint(CONSTRAINT_TABLE) { - values("0.021, 0.021, 0.027",\ - "0.021, 0.021, 0.027",\ - "0.021, 0.021, 0.027"); + values("0.039, 0.039, 0.027",\ + "0.039, 0.039, 0.027",\ + "0.039, 0.039, 0.027"); } } timing(){ timing_type : hold_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.015, 0.021",\ - "0.009, 0.015, 0.021",\ - "0.009, 0.015, 0.021"); + values("-0.004, -0.004, 0.009",\ + "-0.004, -0.004, 0.009",\ + "-0.004, -0.004, 0.009"); } fall_constraint(CONSTRAINT_TABLE) { - values("-0.065, -0.071, -0.175",\ - "-0.065, -0.071, -0.175",\ - "-0.065, -0.071, -0.175"); + values("-0.052, -0.059, -0.132",\ + "-0.052, -0.059, -0.132",\ + "-0.052, -0.059, -0.132"); } } } @@ -241,28 +241,28 @@ cell (sram_2_16_1_scn3me_subm){ timing_type : setup_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.082, 0.088, 0.186",\ - "0.082, 0.088, 0.186",\ - "0.082, 0.088, 0.186"); + values("0.076, 0.076, 0.149",\ + "0.076, 0.076, 0.149",\ + "0.076, 0.076, 0.149"); } fall_constraint(CONSTRAINT_TABLE) { - values("0.021, 0.021, 0.027",\ - "0.021, 0.021, 0.027",\ - "0.021, 0.021, 0.027"); + values("0.039, 0.039, 0.027",\ + "0.039, 0.039, 0.027",\ + "0.039, 0.039, 0.027"); } } timing(){ timing_type : hold_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.015, 0.021",\ - "0.009, 0.015, 0.021",\ - "0.009, 0.015, 0.021"); + values("-0.004, -0.004, 0.009",\ + "-0.004, -0.004, 0.009",\ + "-0.004, -0.004, 0.009"); } fall_constraint(CONSTRAINT_TABLE) { - values("-0.065, -0.071, -0.175",\ - "-0.065, -0.071, -0.175",\ - "-0.065, -0.071, -0.175"); + values("-0.052, -0.059, -0.132",\ + "-0.052, -0.059, -0.132",\ + "-0.052, -0.059, -0.132"); } } } @@ -274,28 +274,28 @@ cell (sram_2_16_1_scn3me_subm){ timing_type : setup_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.082, 0.088, 0.186",\ - "0.082, 0.088, 0.186",\ - "0.082, 0.088, 0.186"); + values("0.076, 0.076, 0.149",\ + "0.076, 0.076, 0.149",\ + "0.076, 0.076, 0.149"); } fall_constraint(CONSTRAINT_TABLE) { - values("0.021, 0.021, 0.027",\ - "0.021, 0.021, 0.027",\ - "0.021, 0.021, 0.027"); + values("0.039, 0.039, 0.027",\ + "0.039, 0.039, 0.027",\ + "0.039, 0.039, 0.027"); } } timing(){ timing_type : hold_rising; related_pin : "clk"; rise_constraint(CONSTRAINT_TABLE) { - values("0.009, 0.015, 0.021",\ - "0.009, 0.015, 0.021",\ - "0.009, 0.015, 0.021"); + values("-0.004, -0.004, 0.009",\ + "-0.004, -0.004, 0.009",\ + "-0.004, -0.004, 0.009"); } fall_constraint(CONSTRAINT_TABLE) { - values("-0.065, -0.071, -0.175",\ - "-0.065, -0.071, -0.175",\ - "-0.065, -0.071, -0.175"); + values("-0.052, -0.059, -0.132",\ + "-0.052, -0.059, -0.132",\ + "-0.052, -0.059, -0.132"); } } } @@ -308,20 +308,20 @@ cell (sram_2_16_1_scn3me_subm){ timing_type :"min_pulse_width"; related_pin : clk; rise_constraint(scalar) { - values("4.375"); + values("2.344"); } fall_constraint(scalar) { - values("4.375"); + values("2.344"); } } timing(){ timing_type :"minimum_period"; related_pin : clk; rise_constraint(scalar) { - values("8.75"); + values("4.688"); } fall_constraint(scalar) { - values("8.75"); + values("4.688"); } } } diff --git a/compiler/tests/golden/sram_2_16_1_scn3me_subm_analytical.lib b/compiler/tests/golden/sram_2_16_1_scn3me_subm_TT_50V_25C_analytical.lib similarity index 96% rename from compiler/tests/golden/sram_2_16_1_scn3me_subm_analytical.lib rename to compiler/tests/golden/sram_2_16_1_scn3me_subm_TT_50V_25C_analytical.lib index 21805aad..52ecdb72 100644 --- a/compiler/tests/golden/sram_2_16_1_scn3me_subm_analytical.lib +++ b/compiler/tests/golden/sram_2_16_1_scn3me_subm_TT_50V_25C_analytical.lib @@ -1,4 +1,4 @@ -library (sram_2_16_1_scn3me_subm_lib){ +library (sram_2_16_1_scn3me_subm_TT_50V_25C_lib){ delay_model : "table_lookup"; time_unit : "1ns" ; voltage_unit : "1v" ; @@ -9,7 +9,7 @@ library (sram_2_16_1_scn3me_subm_lib){ pulling_resistance_unit :"1kohm" ; operating_conditions(TT){ voltage : 5.0 ; - temperature : 25.000 ; + temperature : 25; } input_threshold_pct_fall : 50.0 ; @@ -74,7 +74,7 @@ cell (sram_2_16_1_scn3me_subm){ dont_use : true; map_only : true; dont_touch : true; - area : 2.7; + area : 122426.46; bus(DATA){ bus_type : DATA; @@ -140,14 +140,14 @@ cell (sram_2_16_1_scn3me_subm){ related_pin : "clk"; timing_type : falling_edge; cell_rise(CELL_TABLE) { - values("0.561, 0.608, 1.049",\ - "0.561, 0.608, 1.049",\ - "0.561, 0.608, 1.049"); + values("0.556, 0.603, 1.044",\ + "0.556, 0.603, 1.044",\ + "0.556, 0.603, 1.044"); } cell_fall(CELL_TABLE) { - values("0.561, 0.608, 1.049",\ - "0.561, 0.608, 1.049",\ - "0.561, 0.608, 1.049"); + values("0.556, 0.603, 1.044",\ + "0.556, 0.603, 1.044",\ + "0.556, 0.603, 1.044"); } rise_transition(CELL_TABLE) { values("0.024, 0.081, 0.61",\ diff --git a/compiler/tests/golden/sram_2_16_1_scn3me_subm_TT_50V_25C_pruned.lib b/compiler/tests/golden/sram_2_16_1_scn3me_subm_TT_50V_25C_pruned.lib new file mode 100644 index 00000000..b6fc4525 --- /dev/null +++ b/compiler/tests/golden/sram_2_16_1_scn3me_subm_TT_50V_25C_pruned.lib @@ -0,0 +1,329 @@ +library (sram_2_16_1_scn3me_subm_TT_50V_25C_lib){ + delay_model : "table_lookup"; + time_unit : "1ns" ; + voltage_unit : "1v" ; + current_unit : "1mA" ; + resistance_unit : "1kohm" ; + capacitive_load_unit(1 ,fF) ; + leakage_power_unit : "1mW" ; + pulling_resistance_unit :"1kohm" ; + operating_conditions(TT){ + voltage : 5.0 ; + temperature : 25; + } + + input_threshold_pct_fall : 50.0 ; + output_threshold_pct_fall : 50.0 ; + input_threshold_pct_rise : 50.0 ; + output_threshold_pct_rise : 50.0 ; + slew_lower_threshold_pct_fall : 10.0 ; + slew_upper_threshold_pct_fall : 90.0 ; + slew_lower_threshold_pct_rise : 10.0 ; + slew_upper_threshold_pct_rise : 90.0 ; + + default_cell_leakage_power : 0.0 ; + default_leakage_power_density : 0.0 ; + default_input_pin_cap : 1.0 ; + default_inout_pin_cap : 1.0 ; + default_output_pin_cap : 0.0 ; + default_max_transition : 0.5 ; + default_fanout_load : 1.0 ; + default_max_fanout : 4.0 ; + default_connection_class : universal ; + + lu_table_template(CELL_TABLE){ + variable_1 : input_net_transition; + variable_2 : total_output_net_capacitance; + index_1("0.0125, 0.05, 0.4"); + index_2("2.45605, 9.8242, 78.5936"); + } + + lu_table_template(CONSTRAINT_TABLE){ + variable_1 : related_pin_transition; + variable_2 : constrained_pin_transition; + index_1("0.0125, 0.05, 0.4"); + index_2("0.0125, 0.05, 0.4"); + } + + default_operating_conditions : TT; + + + type (DATA){ + base_type : array; + data_type : bit; + bit_width : 2; + bit_from : 0; + bit_to : 1; + } + + type (ADDR){ + base_type : array; + data_type : bit; + bit_width : 4; + bit_from : 0; + bit_to : 3; + } + +cell (sram_2_16_1_scn3me_subm){ + memory(){ + type : ram; + address_width : 4; + word_width : 2; + } + interface_timing : true; + dont_use : true; + map_only : true; + dont_touch : true; + area : 122426.46; + + bus(DATA){ + bus_type : DATA; + direction : inout; + max_capacitance : 78.5936; + three_state : "!OEb & !clk"; + memory_write(){ + address : ADDR; + clocked_on : clk; + } + memory_read(){ + address : ADDR; + } + pin(DATA[1:0]){ + internal_power(){ + when : "OEb & !clk"; + rise_power(scalar){ + values("11.756062"); + } + fall_power(scalar){ + values("7.1840422"); + } + } + timing(){ + timing_type : setup_rising; + related_pin : "clk"; + rise_constraint(CONSTRAINT_TABLE) { + values("0.076, 0.076, 0.149",\ + "0.076, 0.076, 0.149",\ + "0.076, 0.076, 0.149"); + } + fall_constraint(CONSTRAINT_TABLE) { + values("0.039, 0.039, 0.027",\ + "0.039, 0.039, 0.027",\ + "0.039, 0.039, 0.027"); + } + } + timing(){ + timing_type : hold_rising; + related_pin : "clk"; + rise_constraint(CONSTRAINT_TABLE) { + values("-0.004, -0.004, 0.009",\ + "-0.004, -0.004, 0.009",\ + "-0.004, -0.004, 0.009"); + } + fall_constraint(CONSTRAINT_TABLE) { + values("-0.052, -0.059, -0.132",\ + "-0.052, -0.059, -0.132",\ + "-0.052, -0.059, -0.132"); + } + } + internal_power(){ + when : "!OEb & !clk"; + rise_power(scalar){ + values("10.730552"); + } + fall_power(scalar){ + values("10.584523"); + } + } + timing(){ + timing_sense : non_unate; + related_pin : "clk"; + timing_type : falling_edge; + cell_rise(CELL_TABLE) { + values("0.458, 0.503, 0.87",\ + "0.461, 0.505, 0.873",\ + "0.5, 0.544, 0.911"); + } + cell_fall(CELL_TABLE) { + values("0.573, 0.649, 1.249",\ + "0.576, 0.651, 1.252",\ + "0.616, 0.69, 1.289"); + } + rise_transition(CELL_TABLE) { + values("0.153, 0.232, 1.084",\ + "0.153, 0.233, 1.084",\ + "0.156, 0.236, 1.084"); + } + fall_transition(CELL_TABLE) { + values("0.277, 0.355, 1.499",\ + "0.277, 0.357, 1.499",\ + "0.278, 0.362, 1.499"); + } + } + } + } + + bus(ADDR){ + bus_type : ADDR; + direction : input; + capacitance : 9.8242; + max_transition : 0.4; + fanout_load : 1.000000; + pin(ADDR[3:0]){ + timing(){ + timing_type : setup_rising; + related_pin : "clk"; + rise_constraint(CONSTRAINT_TABLE) { + values("0.076, 0.076, 0.149",\ + "0.076, 0.076, 0.149",\ + "0.076, 0.076, 0.149"); + } + fall_constraint(CONSTRAINT_TABLE) { + values("0.039, 0.039, 0.027",\ + "0.039, 0.039, 0.027",\ + "0.039, 0.039, 0.027"); + } + } + timing(){ + timing_type : hold_rising; + related_pin : "clk"; + rise_constraint(CONSTRAINT_TABLE) { + values("-0.004, -0.004, 0.009",\ + "-0.004, -0.004, 0.009",\ + "-0.004, -0.004, 0.009"); + } + fall_constraint(CONSTRAINT_TABLE) { + values("-0.052, -0.059, -0.132",\ + "-0.052, -0.059, -0.132",\ + "-0.052, -0.059, -0.132"); + } + } + } + } + + pin(CSb){ + direction : input; + capacitance : 9.8242; + timing(){ + timing_type : setup_rising; + related_pin : "clk"; + rise_constraint(CONSTRAINT_TABLE) { + values("0.076, 0.076, 0.149",\ + "0.076, 0.076, 0.149",\ + "0.076, 0.076, 0.149"); + } + fall_constraint(CONSTRAINT_TABLE) { + values("0.039, 0.039, 0.027",\ + "0.039, 0.039, 0.027",\ + "0.039, 0.039, 0.027"); + } + } + timing(){ + timing_type : hold_rising; + related_pin : "clk"; + rise_constraint(CONSTRAINT_TABLE) { + values("-0.004, -0.004, 0.009",\ + "-0.004, -0.004, 0.009",\ + "-0.004, -0.004, 0.009"); + } + fall_constraint(CONSTRAINT_TABLE) { + values("-0.052, -0.059, -0.132",\ + "-0.052, -0.059, -0.132",\ + "-0.052, -0.059, -0.132"); + } + } + } + + pin(OEb){ + direction : input; + capacitance : 9.8242; + timing(){ + timing_type : setup_rising; + related_pin : "clk"; + rise_constraint(CONSTRAINT_TABLE) { + values("0.076, 0.076, 0.149",\ + "0.076, 0.076, 0.149",\ + "0.076, 0.076, 0.149"); + } + fall_constraint(CONSTRAINT_TABLE) { + values("0.039, 0.039, 0.027",\ + "0.039, 0.039, 0.027",\ + "0.039, 0.039, 0.027"); + } + } + timing(){ + timing_type : hold_rising; + related_pin : "clk"; + rise_constraint(CONSTRAINT_TABLE) { + values("-0.004, -0.004, 0.009",\ + "-0.004, -0.004, 0.009",\ + "-0.004, -0.004, 0.009"); + } + fall_constraint(CONSTRAINT_TABLE) { + values("-0.052, -0.059, -0.132",\ + "-0.052, -0.059, -0.132",\ + "-0.052, -0.059, -0.132"); + } + } + } + + pin(WEb){ + direction : input; + capacitance : 9.8242; + timing(){ + timing_type : setup_rising; + related_pin : "clk"; + rise_constraint(CONSTRAINT_TABLE) { + values("0.076, 0.076, 0.149",\ + "0.076, 0.076, 0.149",\ + "0.076, 0.076, 0.149"); + } + fall_constraint(CONSTRAINT_TABLE) { + values("0.039, 0.039, 0.027",\ + "0.039, 0.039, 0.027",\ + "0.039, 0.039, 0.027"); + } + } + timing(){ + timing_type : hold_rising; + related_pin : "clk"; + rise_constraint(CONSTRAINT_TABLE) { + values("-0.004, -0.004, 0.009",\ + "-0.004, -0.004, 0.009",\ + "-0.004, -0.004, 0.009"); + } + fall_constraint(CONSTRAINT_TABLE) { + values("-0.052, -0.059, -0.132",\ + "-0.052, -0.059, -0.132",\ + "-0.052, -0.059, -0.132"); + } + } + } + + pin(clk){ + clock : true; + direction : input; + capacitance : 9.8242; + timing(){ + timing_type :"min_pulse_width"; + related_pin : clk; + rise_constraint(scalar) { + values("2.344"); + } + fall_constraint(scalar) { + values("2.344"); + } + } + timing(){ + timing_type :"minimum_period"; + related_pin : clk; + rise_constraint(scalar) { + values("4.688"); + } + fall_constraint(scalar) { + values("4.688"); + } + } + } + } +} diff --git a/compiler/tests/testutils.py b/compiler/tests/testutils.py index c7d62071..76c23ae8 100644 --- a/compiler/tests/testutils.py +++ b/compiler/tests/testutils.py @@ -1,8 +1,9 @@ -import unittest +import unittest,warnings import sys,os,glob sys.path.append(os.path.join(sys.path[0],"..")) import globals from globals import OPTS +import debug class openram_test(unittest.TestCase): """ Base unit test that we have some shared classes in. """ @@ -17,8 +18,8 @@ class openram_test(unittest.TestCase): for f in files: os.remove(f) - def local_check(self, a): - + def local_check(self, a, final_verification=False): + tempspice = OPTS.openram_temp + "temp.sp" tempgds = OPTS.openram_temp + "temp.gds" @@ -34,17 +35,17 @@ class openram_test(unittest.TestCase): try: - self.assertTrue(verify.run_lvs(a.name, tempgds, tempspice)==0) + self.assertTrue(verify.run_lvs(a.name, tempgds, tempspice, final_verification)==0) except: self.reset() self.fail("LVS mismatch: {}".format(a.name)) - self.cleanup() + self.reset() + if OPTS.purge_temp: + self.cleanup() def cleanup(self): """ Reset the duplicate checker and cleanup files. """ - self.reset() - files = glob.glob(OPTS.openram_temp + '*') for f in files: # Only remove the files diff --git a/compiler/verify/calibre.py b/compiler/verify/calibre.py index e72aa965..f679bb44 100644 --- a/compiler/verify/calibre.py +++ b/compiler/verify/calibre.py @@ -137,9 +137,11 @@ def run_drc(cell_name, gds_name): return errors -def run_lvs(cell_name, gds_name, sp_name): +def run_lvs(cell_name, gds_name, sp_name, final_verification=False): """Run LVS check on a given top-level name which is - implemented in gds_name and sp_name. """ + implemented in gds_name and sp_name. Final verification will + ensure that there are no remaining virtual conections. """ + from tech import drc lvs_rules = drc["lvs_rules"] lvs_runset = { @@ -154,7 +156,6 @@ def run_lvs(cell_name, gds_name, sp_name): 'lvsPowerNames': 'vdd', 'lvsGroundNames': 'gnd', 'lvsIncludeSVRFCmds': 1, - 'lvsSVRFCmds': '{VIRTUAL CONNECT NAME VDD? GND? ?}', 'lvsIgnorePorts': 1, 'lvsERCDatabase': OPTS.openram_temp + cell_name + ".erc.results", 'lvsERCSummaryFile': OPTS.openram_temp + cell_name + ".erc.summary", @@ -162,10 +163,18 @@ def run_lvs(cell_name, gds_name, sp_name): 'lvsMaskDBFile': OPTS.openram_temp + cell_name + ".maskdb", 'cmnFDILayerMapFile': drc["layer_map"], 'cmnFDIUseLayerMap': 1, - 'cmnVConnectNames': 'vdd, gnd', + 'lvsRecognizeGates': 'NONE' #'cmnVConnectNamesState' : 'ALL', #connects all nets with the same name } + # This should be removed for final verification + if not final_verification: + lvs_runset['cmnVConnectReport']=1 + lvs_runset['cmnVConnectNamesState']='SOME' + lvs_runset['cmnVConnectNames']='vdd gnd' + + + # write the runset file f = open(OPTS.openram_temp + "lvs_runset", "w") for k in sorted(lvs_runset.iterkeys()): diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index f521fac9..b2e66aa2 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -44,8 +44,8 @@ EOF 3. netgen can perform LVS with: #!/bin/sh netgen -noconsole <0: + # debug.warning("Pins altered to match in {}.".format(cell_name)) + + total_errors = len(propertyerrors) + len(incorrect) # If we want to ignore property errors #total_errors = len(incorrect) #if len(propertyerrors)>0: @@ -236,7 +244,7 @@ def run_lvs(cell_name, gds_name, sp_name): # Just print out the whole file, it is short. for e in results: debug.info(1,e.strip("\n")) - debug.error("LVS mismatch (results in {}lvs.results)".format(OPTS.openram_temp)) + debug.error("LVS mismatch (results in {})".format(resultsfile)) return total_errors diff --git a/docs/figs/Array.svg b/docs/figs/Array.svg deleted file mode 100644 index 419083d3..00000000 --- a/docs/figs/Array.svg +++ /dev/null @@ -1,1475 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - Bl Br - - - - - Bl Br - - - - - Bl Br - - - - - Bl Br - - - - - - - - - - - Bl Br - Bl Br - Bl Br - Bl Br - Col.Mux - Cell - Cell - Cell - Cell - Cell - Cell - Cell - Cell - - - - - - - - - - Array - - - - - Bl Br - - - - - Bl Br - - - - - Bl Br - - - - - Bl Br - - Cell - Cell - Cell - Cell - Cell - Cell - Cell - Cell - - - - - - - - - - - - - - - - - - Bl Br - Bl Br - Bl Br - Bl Br - Precharge - - diff --git a/docs/figs/cell_view_1024_16.png b/docs/figs/cell_view_1024_16.png deleted file mode 100644 index f85358c7..00000000 Binary files a/docs/figs/cell_view_1024_16.png and /dev/null differ diff --git a/docs/figs/cell_view_64_4.png b/docs/figs/cell_view_64_4.png deleted file mode 100644 index 12e39112..00000000 Binary files a/docs/figs/cell_view_64_4.png and /dev/null differ diff --git a/docs/figs/column_mux_schem.pdf b/docs/figs/column_tree_mux.pdf similarity index 100% rename from docs/figs/column_mux_schem.pdf rename to docs/figs/column_tree_mux.pdf diff --git a/docs/figs/column_mux_schem.svg b/docs/figs/column_tree_mux.svg similarity index 100% rename from docs/figs/column_mux_schem.svg rename to docs/figs/column_tree_mux.svg diff --git a/docs/figs/decoder_to _array.svg b/docs/figs/decoder_to _array.svg deleted file mode 100644 index 9b7499f4..00000000 --- a/docs/figs/decoder_to _array.svg +++ /dev/null @@ -1,409 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - Address Decoder - - - - Vdd - Word Line - Vss - - - - Vdd - Word Line - Vss - - - - - Array - - - } - } - N-Well - P-Well - - diff --git a/docs/figs/layout_view_1024_16.png b/docs/figs/layout_view_1024_16.png deleted file mode 100644 index a97bfe63..00000000 Binary files a/docs/figs/layout_view_1024_16.png and /dev/null differ diff --git a/docs/figs/layout_view_64_4.png b/docs/figs/layout_view_64_4.png deleted file mode 100644 index 44e7b060..00000000 Binary files a/docs/figs/layout_view_64_4.png and /dev/null differ diff --git a/docs/figs/nand2.pdf b/docs/figs/nand2.pdf deleted file mode 100644 index e6bda803..00000000 Binary files a/docs/figs/nand2.pdf and /dev/null differ diff --git a/docs/figs/nand3.pdf b/docs/figs/nand3.pdf deleted file mode 100644 index b5f91a52..00000000 Binary files a/docs/figs/nand3.pdf and /dev/null differ diff --git a/docs/figs/precharge_schem.pdf b/docs/figs/precharge_schem.pdf index d1fb1f0e..f79363a5 100644 Binary files a/docs/figs/precharge_schem.pdf and b/docs/figs/precharge_schem.pdf differ diff --git a/docs/figs/precharge_schem.svg b/docs/figs/precharge_schem.svg index 9323e52a..1ad9f6d8 100644 --- a/docs/figs/precharge_schem.svg +++ b/docs/figs/precharge_schem.svg @@ -25,13 +25,13 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="1" - inkscape:cx="161.5" + inkscape:cx="20" inkscape:cy="520" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" - inkscape:window-width="1280" - inkscape:window-height="752" + inkscape:window-width="3440" + inkscape:window-height="1392" inkscape:window-x="0" inkscape:window-y="0" inkscape:window-maximized="1"> @@ -185,7 +185,7 @@ id="tspan4519" x="184" y="577.36218" - style="font-size:16px;line-height:1.25;font-family:sans-serif">BL + style="font-size:16px;line-height:1.25;font-family:sans-serif">bl BL_bar + style="font-size:16px;line-height:1.25;font-family:sans-serif">br VDD + style="font-size:16px;line-height:1.25;font-family:sans-serif">vdd CLK + style="font-size:16px;line-height:1.25;font-family:sans-serif">en + inkscape:version="0.92.2 5c3e80d, 2017-08-06" + sodipodi:docname="sense_amp_schem.svg"> image/svg+xml - + @@ -55,37 +55,6 @@ inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1"> - - - - - - - - - - - @@ -148,37 +117,6 @@ inkscape:connector-curvature="0" /> - - - - - - - - - - - @@ -357,18 +295,18 @@ id="path4592" inkscape:connector-curvature="0" /> + transform="matrix(1.25,0,0,1,125,112.20718)"> VDD + y="172.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">vdd DATA + y="297.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">DATA BL_bar + x="621" + y="577.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">br BL + y="580.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">bl EN + y="588.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">en EN + x="538" + y="382.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">en EN + x="177.87868" + y="376.02765" + style="font-size:16px;line-height:1.25;font-family:sans-serif">en + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/figs/sram_overview.pdf b/docs/figs/sram_overview.pdf index 153b1ac4..4a533d27 100644 Binary files a/docs/figs/sram_overview.pdf and b/docs/figs/sram_overview.pdf differ diff --git a/docs/figs/sram_overview.svg b/docs/figs/sram_overview.svg index 1f399816..f80583c7 100644 --- a/docs/figs/sram_overview.svg +++ b/docs/figs/sram_overview.svg @@ -14,8 +14,8 @@ height="600" id="svg15111" version="1.1" - inkscape:version="0.47 r22583" - sodipodi:docname="sram_overview.eps"> + inkscape:version="0.91 r13725" + sodipodi:docname="sram_overview.svg"> + + + + + + @@ -396,7 +424,7 @@ image/svg+xml - + @@ -594,7 +622,7 @@ id="tspan16259-3">Driver UpperLowerAddress LowerUpperAddress 6T Cell - + + + + + + + diff --git a/docs/figs/timing_read.pdf b/docs/figs/timing_read.pdf index 850a0704..6f859889 100644 Binary files a/docs/figs/timing_read.pdf and b/docs/figs/timing_read.pdf differ diff --git a/docs/figs/timing_read.svg b/docs/figs/timing_read.svg index f7c218de..16fafe00 100644 --- a/docs/figs/timing_read.svg +++ b/docs/figs/timing_read.svg @@ -13,7 +13,7 @@ height="744.09448" id="svg3956" version="1.1" - inkscape:version="0.48.3.1 r9886" + inkscape:version="0.92.2 5c3e80d, 2017-08-06" sodipodi:docname="timing_read.svg"> @@ -248,15 +248,15 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="1" - inkscape:cx="427.64919" + inkscape:cx="286.14919" inkscape:cy="216.91628" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" - inkscape:window-width="1366" - inkscape:window-height="744" + inkscape:window-width="3440" + inkscape:window-height="1392" inkscape:window-x="0" - inkscape:window-y="24" + inkscape:window-y="0" inkscape:window-maximized="1"> CLK + y="372.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">CLK ADDR + y="452.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">ADDR CSb + y="532.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">CSb OEb + y="612.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">OEb WEb + y="692.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">WEb DATA OUT + y="852.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">DATA OUT A0 + y="452.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">A0 A1 - - - - - - - - + y="452.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">A1 + + + + D0 + x="555" + y="851.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">D0 D1 + x="719" + y="851.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">D1 Setup + style="font-size:12px;line-height:1.25;font-family:sans-serif">Setup Hold + style="font-size:12px;line-height:1.25;font-family:sans-serif">Hold Setup + style="font-size:12px;line-height:1.25;font-family:sans-serif">Setup Hold + style="font-size:12px;line-height:1.25;font-family:sans-serif">Hold Read Delay + x="379" + y="840.36218" + style="font-size:14px;line-height:1.25;font-family:sans-serif">Read Delay Setup + style="font-size:12px;line-height:1.25;font-family:sans-serif">Setup SCLK + y="772.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">SCLK + + diff --git a/docs/figs/timing_write.pdf b/docs/figs/timing_write.pdf index 74811468..810ec2bb 100644 Binary files a/docs/figs/timing_write.pdf and b/docs/figs/timing_write.pdf differ diff --git a/docs/figs/timing_write.svg b/docs/figs/timing_write.svg index eb5290c6..6bbfdcb5 100644 --- a/docs/figs/timing_write.svg +++ b/docs/figs/timing_write.svg @@ -13,7 +13,7 @@ height="744.09448" id="svg3956" version="1.1" - inkscape:version="0.48.3.1 r9886" + inkscape:version="0.92.2 5c3e80d, 2017-08-06" sodipodi:docname="timing_write.svg"> @@ -332,15 +332,15 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="1" - inkscape:cx="412.2745" + inkscape:cx="270.7745" inkscape:cy="329.51856" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" - inkscape:window-width="1366" - inkscape:window-height="744" + inkscape:window-width="3440" + inkscape:window-height="1392" inkscape:window-x="0" - inkscape:window-y="24" + inkscape:window-y="0" inkscape:window-maximized="1"> CLK + y="372.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">CLK ADDR + y="452.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">ADDR CSb + y="532.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">CSb OEb + y="692.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">OEb WEb + y="612.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">WEb DATA IN + x="59" + y="785.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">DATA IN A0 + y="452.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">A0 A1 + y="452.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">A1 D0 + x="403" + y="797.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">D0 D1 + x="621" + y="784.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif;fill:#000000">D1 Setup + style="font-size:12px;line-height:1.25;font-family:sans-serif">Setup Hold + style="font-size:12px;line-height:1.25;font-family:sans-serif">Hold Setup + style="font-size:12px;line-height:1.25;font-family:sans-serif">Setup Hold + style="font-size:12px;line-height:1.25;font-family:sans-serif">Hold Setup + style="font-size:12px;line-height:1.25;font-family:sans-serif">Setup - - WD_EN - - Setup + x="369" + y="765.36218" + style="font-size:12px;line-height:1.25;font-family:sans-serif">Setup Hold + x="432" + y="766.36218" + style="font-size:12px;line-height:1.25;font-family:sans-serif">Hold + inkscape:connector-curvature="0" /> + inkscape:connector-curvature="0" /> + inkscape:connector-curvature="0" /> D0 + x="550" + y="863.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">D0 D1 + x="770" + y="863.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif;fill:#000000">D1 XXMem Cell + style="font-size:10px;line-height:1.25;font-family:sans-serif;text-align:center;text-anchor:middle">Mem Cell + inkscape:connector-curvature="0" /> Write Delay + x="421" + y="855.36218" + style="font-size:13px;line-height:1.25;font-family:sans-serif">Write Delay + diff --git a/docs/figs/write_driver_schem.pdf b/docs/figs/write_driver_schem.pdf index 53427630..e943ee80 100644 Binary files a/docs/figs/write_driver_schem.pdf and b/docs/figs/write_driver_schem.pdf differ diff --git a/docs/figs/write_driver_schem.svg b/docs/figs/write_driver_schem.svg index 05c2693f..3882dffc 100644 --- a/docs/figs/write_driver_schem.svg +++ b/docs/figs/write_driver_schem.svg @@ -13,8 +13,8 @@ height="1052.3622047" id="svg4759" version="1.1" - inkscape:version="0.48.3.1 r9886" - sodipodi:docname="write_driver.svg"> + inkscape:version="0.92.2 5c3e80d, 2017-08-06" + sodipodi:docname="write_driver_schem.svg"> image/svg+xml - + @@ -113,16 +113,16 @@ inkscape:connector-curvature="0" /> VDD + sodipodi:role="line" + style="font-size:16px;line-height:1.25;font-family:sans-serif">vdd EN + y="536.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">en @@ -583,15 +583,15 @@ inkscape:connector-curvature="0" /> DATA + y="356.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">DATA BL + y="476.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">bl BL_bar + y="477.36218" + style="font-size:16px;line-height:1.25;font-family:sans-serif">br diff --git a/docs/implementation.tex b/docs/implementation.tex index a45db539..187bcd48 100644 --- a/docs/implementation.tex +++ b/docs/implementation.tex @@ -315,19 +315,33 @@ OpenRAM, the default technology is FreePDK45, which has it own technolony directory in the trunk. The technology-specific directory should consist of the following: \begin{itemize} +\item Technology Setup FIle - In \verb|/techdir/setup_scripts|, there + should be a Python file that sets up the PDK and defines anything + necessary for a given technology. This file should be named + \verb|setup_openram_.py| where techname is the name used + to identify it in configuration scripts. \item Technology-Specific Parameters - These parameters should include layer numbers and any design rules that may be needed for generating dynamic designs (DRC rules). The parameters should be added in - \verb|/techdir/tech/tech.py| and layer map in the \verb|/techdir|. + \verb|techname/tech/tech.py| and optinally in a \verb|techname/layer.map| for + DRC/LVS streaming. \item Library Cells - The library cells and corresponding spice - netlists should be added to the \verb|/gds_lib| and \verb|/sp_lib| - directories. -\item Portation Functions - Some of the dynamically generated cells - may need helper functions to deal with technology-specific - requirements. Additional, tech-specific, functions should be added - to the \verb|/techdir|. + netlists should be added to the \verb|techname/gds_lib| and + \verb|techname/sp_lib| directories. +\item Spice Models - If models are not supplied in the PDK, they can be + placed in the technology directory as done in SCMOS. \end{itemize} +The height and width of library cells is determined by the bounding +box of all geometries. Sometimes this is not desired, for example, +when a rail must be shared. In this case, the boundary layer in the +technology file is used to define the height and width of the cell. + +Pins are recognized in library cells by the largest rectangle that +encloses the pin label text. Multiple pins with the same name are +supported. Pins with the same name such as gnd are assumed to be +``must connect'' which requires that they later be connected. + For more information regarding the technology directory and how to set one up for a new technology, refer to Section~\ref{sec:porting} @@ -342,30 +356,32 @@ the command line. The \verb|DRC_LVS()| function saves a GDSII file and a Spice file into a temporary directory and then calls two functions to perform DRC and LVS that are tool-dependent. -A reference implementation for the DRC and LVS functions are provided -for Cadence Calibre since this is the most common DRC/LVS tool. Each -of these functions generates a batch-mode ``runset'' file which -contains the options to correctly run DRC and LVS. The functions then -parse the batch mode output for any potential errors and returns the -number of errors encountered. +Wrapper implementation for DRC and LVS functions are provided for the +open-source tools Magic+Netgen and the commercial tool, Cadence +Calibre. Each of these functions generates a batch-mode script or runset +file which contains the options to correctly run DRC and LVS. The +functions then parse the batch mode output for any potential errors +and returns the number of errors encountered. The function \verb|run_drc()| requires a cell name and a GDSII file. The cell name corresponds to the top level cell in the GDSII -file. It also uses the layer map file for the technology to correctly -import the GDSII file into the Cadence database to perform DRC. The -function returns the number of DRC violations. +file. For Calibre, it also uses the layer map file for the technology +to correctly import the GDSII file into the Cadence database to +perform DRC. The function returns the number of DRC violations. The function \verb|run_lvs()| requires a cell name, a GDSII file, and -a Spice file. Calibre will extract an extracted Spice netlist from the -GDSII file and will then compare this netlist with the OpenRAM Spice -netlist. The function returns the number of uncompared and unmatched -devices/nets in the design. +a Spice file. Magic or Calibre will extract an extracted Spice netlist +from the GDSII file and will then compare this netlist with the +OpenRAM Spice netlist. The function returns the number of errors +encountered if there is an LVS mismatch. + For both DRC and LVS, the summary file and other report files are left in the OpenRAM temporary directory after DRC/LVS is run. These report files can be examined to further understand why errors were -encountered. In addition, by increasing the debug level, the command -line to re-create the DRC/LVS check can be obtained and run manually. +encountered. In addition, by increasing the debug level with one or +more ``-v'' command-line parametres, the command to re-create the +DRC/LVS check can be obtained and run manually. diff --git a/docs/intro.tex b/docs/intro.tex index 5da2f731..a83065b9 100644 --- a/docs/intro.tex +++ b/docs/intro.tex @@ -20,12 +20,9 @@ The specific features of OpenRAM are: \item \textbf{Memory Array Generation} - Currently, OpenRAM supports simple 1 read/write port synchronous - memories, but it will be extended to multi-port memories, register - files, and asynchronous memories in the future. The generation - includes features such as automatic word-line driver sizing, - efficient decoder sizing, multiple-word column support, and - self-timing with replica bitlines. + Currently, OpenRAM includes features such as automatic word-line + driver sizing, efficient decoder sizing, multiple-word column + support, and self-timing with replica bitlines. \item \textbf{Portability and Extensibility} @@ -41,11 +38,11 @@ The specific features of OpenRAM are: to distribute the technology information of others commercial technologies soon. - OpenRAM makes calls to commercial circuit simulators and DRC/LVS - tools in an abstracted way for circuit simulation and - verification. This enables adaptation to other design - methodologies. However, it also supports a completely open-source - platform for older technologies. + OpenRAM makes calls to both open-source or commercial circuit + simulators and DRC/LVS tools in an abstracted way for circuit + simulation and verification. This enables adaptation to other design + methodologies. It supports a completely open-source + platform for older SCMOS technologies. \item \textbf{Timing and Power Characterization} @@ -74,7 +71,9 @@ The specific features of OpenRAM are: \subsection{Requirements} -Development is done on Ubuntu or MacOS systems with Python 2.7. +Development is done on Ubuntu or MacOS systems with Python 2.7. It +requires a few common Python libraries such as numpy, scipy (soon, for +optimization) along with standard Python libraries (os, sys, etc.). \subsubsection{Timing Verification Tools} @@ -92,7 +91,7 @@ OpenRAM can use the following circuit simulators and possibly others if they support the Spice3 file format: \begin{itemize} \item HSpice I-2013.12-1 or later - \item ngSpice 26 \url{http://ngspice.sourceforge.net/} + \item ngspice 26 \url{http://ngspice.sourceforge.net/} \item CustomSim (xa) M-2017.03-SP5 or later \end{itemize} @@ -119,14 +118,15 @@ LVS can be done with: \subsubsection{Technology Files} -To work with FreePDK45, you must install the FreePDK baseline kit from: +To work with FreePDK45, you must install the FreePDK baseline kit from:\\ \url{https://www.eda.ncsu.edu/wiki/FreePDK45:Contents} We have included an example Calibre DRC deck for MOSIS SCMOS design -rules, but DRC with Magic relies on its own design rules: -\url{https://www.mosis.com/files/scmos/scmos.pdf} We require the -format 32 or later to enable stacked vias which is included with -Qflow: +rules, but DRC with Magic relies on the MOSIS scalable design +rules:\\ +\url{https://www.mosis.com/files/scmos/scmos.pdf}.\\ +We require the format 32 or later to enable stacked vias which is +included with Qflow: \begin{verbatim} git clone http://opencircuitdesign.com/qflow cp tech/osu050/SCN3ME_SUBM.30.tech @@ -137,15 +137,19 @@ DRCLVS\_HOME environment variable. \subsubsection{Spice Models} -FreePDK45 comes with a spice device model. Once this is installed, it -is used. +FreePDK45 comes with a spice device model. Once this is installed and +the PDK\_DIR environment variable for FreePDK45 is set, these spice +models are used. SCMOS, however, does not come with a device spice model. This must be obtained from MOSIS or another vendor. We use the ON Semiconductor -0.5um device models. +0.5um device models, but are unable to distribute them. We have included our +own generic spice models for simulation of SCMOS, but we recommend that +you replace these with more accurate foundry models. You can over-ride the location of the spice models with the -SPICE\_MODEL\_DIR environment variable. +SPICE\_MODEL\_DIR environment variable to ensure that they do not +``creep'' into the OpenRAM git repository. @@ -156,7 +160,7 @@ to make it relocatable in a variety of user scenarios. Specifically, the user may want technology directories that are separate from OpenRAM. Or, the user may want to have several versions of OpenRAM. This is done with the folowing required environment -variables: specifically: +variables: \begin{itemize} \item OPENRAM\_HOME defines the location of the compiler source directory. \item OPENRAM\_TECH defines the location of the OpenRAM technology @@ -165,12 +169,12 @@ variables: specifically: Other environmental variables and additional required paths for specific technologies are dynamically added during runtime by sourcing -a technology setup script. These are located in the +a technology setup script. These are mostly PDK-specific. These are located in the "\$OPENRAM\_TECH/setup\_scripts" directory. Example scripts for SCMOS and -FreePDK45 are included with the distribution. These setup any things -needed by the PDK. +FreePDK45 are included with the distribution. -\subsection{Design Flow} + +%\subsection{Design Flow} %% % high-level org @@ -209,13 +213,14 @@ needed by the PDK. \subsection{Usage} -The OpenRAM compiler rquires a single argument of a configuration +The OpenRAM compiler requires a single argument of a configuration file. The configuration file specifies, at a minimum, the memory size parameters in terms of the number of words, word size (in bits), and number of banks. By default, OpenRAM will chose the number of columns -to make the memory reasonably square. Commonly, the configuration file -also includes parameters for the output path, base output file name, -and technology of an SRAM. +to make the memory reasonably square. Other common configuration +parameters are the output path and base filename, characterization +corners (including the supply voltage), number of ports, technology +node, etc. The configuration file can be used to over-ride any option in the options.py file. Many of these can also be controlled by the command-line diff --git a/docs/modules.tex b/docs/modules.tex index 8c152863..a232cd1f 100644 --- a/docs/modules.tex +++ b/docs/modules.tex @@ -10,25 +10,36 @@ of the possible circuits that can be adapted into a SRAM architecture; refer to Section~\ref{sec:implementation} for more information on adding different module designs to the compiler. -Each module has a corresponding python class in the \verb|compiler| -directory. These classes are used to generate both the GDSII layout -and spice netlists. Each module can consist of library cells as -discussed in Section~\ref{sec:techdir}, paramterized cells in -Section~\ref{sec:parameterized} or other modules. A discussion of the -design hierarchy and how to implement a module is provided in -Section~\ref{sec:design}. +Data structures for schematic and layout are provided in the +\verb|base| directory. These implement a generic design object and +have many auxiliary functions for routing, pin access, placement, +DRC/LVS, etc. These are discussed further in +Section~\ref{sec:implementation}. + +Each module has a corresponding Python class in the +\verb|compiler/modules| directory. These classes are used to generate +both the GDSII layout and spice netlists. A module can consist of +hard library cells (Section~\ref{sec:techdir}), paramterized +cells (Section~\ref{sec:parameterized}) or other modules. When combining modules at any level of hierarchy, DRC rules for minimum spacing of metals, wells, etc. must be followed and DRC and -LVS are run by default after each hierarchical module's creation. +LVS are run by default after each hierarchical module's creation. A +module is responsible for creating its own pins to enable routing +at the next level up in the hierarchy. A module must also define its +height and width assuming a (0,0) offset for the lower-left coordinate +to aid with placement. \subsection{The Bitcell and Bitcell Array} \label{sec:bitcellarray} -The 6T cell is the most commonly used memory cell in SRAM devices. It -is named a 6T cell because it consist of 6 transistors: 2 access -transistors and 2 cross coupled inverters as shown in +OpenRAM can work with any cell as the bitcell. This could be a foundry +created one or a user design rule cell for experiments. In addition, +it could be a common 6T cell or it could be replaced with an 8T, 10T +or other cell, depending on needs. + +By default, OpenRAM uses a standard 6T cell as shown in Figure~\ref{fig:6t_cell}. The cross coupled inverters hold a single data bit that can either be driven into, or read from the cell by the bitlines. The access transistors are used to isolate the cell from @@ -37,70 +48,52 @@ accessed. \begin{figure}[h!] \centering -\includegraphics[scale=.9]{./figs/cell_6t_schem.pdf} -\caption{Schematic of 6T cell.} +\includegraphics[scale=.9]{figs/cell_6t_schem.pdf} +\caption{Standard 6T cell.} \label{fig:6t_cell} \end{figure} -% memory cell operation -The 6T cell can be accessed to perform the two main operation -associated with memory: reading and writing. When a read is to be -performed, both bitlines are precharged to VDD. This precharging is -done during the first half of the read cycle and is handled by the -precharge circuitry. In the second half of the read cycle the -wordline is asserted, which enable the access transistors. If a 1 is -stored in the cell then BLB is discharged to Gnd and BL is pulled up -to Vdd. Conversely, if the value stored is a 0, then BL is discharged -to Gnd and BLB is pulled up to Vdd. While performing a write -operation, both bitlines are also precharged to Vdd during the first -half of the write cycle. Again, the world line is asserted, and the -access transistors are enabled. The value that is to be written into -the cell is applied to BL, and its complement is applied to BLB. The -drivers that are applying the signals to the bitlines must be -appropriately sized so that the previous value in the cell can be -overwritten. - % tiling memory cells The 6T cells are tiled together in both the horizontal and vertical -directions to make up the memory array. The size of the memory array -is directly related to the numbers of words, and the size of those -words, that will need to be stored in the RAM. For example, an 8kb -memory with a word size of 8 bits could be implemented as 8 columns -and 1024 rows. +directions to make up the memory array. % keeping it square -It is common practice to keep the aspect ratio of memory array as -square as possible\footnote{Future versions will consider optimizing - delay and/or power as well.}. This helps to make sure that the -bitlines do not become too long, which can increase the bitline -capacitance, slow down the operation and lead to more leakage. To -make the design ``more square'', multiple words can share rows by -interleaving the bits of each word. If the previous 8kb memory was -rearranged to allow 2 words per row, then the array would have 16 -columns and 512 rows. +It is common practice to keep the aspect ratio of a memory array +roughly ``square'' to ensure that the bitlines and wordlines do not +become too long. If the bitlines are too long, this can increase the +bitline capacitance, slow down the operation and lead to bitline +leakage problems. To make an array ``more square'', multiple words +can share rows by interleaving the bits of each word. The column mux +in Section~\ref{sec:column_mux} is responsbile for selecting a subset +of bitcells in a row to extract a word during read and write +operations. % memory cell is a library cell -In OpenRAM, we provide a library cell for the 6T cell so that users -can easily swap in different memory cell designs. The memory cell is -the most important cell in the RAM and should be customized to -minimize area and optimize performance. The memory cell is the most -replicated cell in the RAM; minimizing its size can have a drastic -effext on the overall size of the RAM. Also, the transitors in the cell -must be carefully sized to allow for correct read and write operation -as well as protection against corruption. +In OpenRAM, we provide a library cell for the 6T cell that can be +swapped with a fab memory cell, if available. The transitors in the +cell are sized appropriately considering read and write noise margins. % bitcell and bitcell_array classes -The \verb|bitcell| class in \verb|bitcell.py| instantiates a single -memory cell and is usually a pre-made library cell. The -\verb|bitcell_array| class in \verb|bitcell_array.py| dynamically -implements the memory cell array by instantiating a single memory cell -according to the number of rows and columns. During the tiling -process, the cells are abutted so that all bitlines and word lines are -connected in the vertical and horizontal directions respectively. In -order to share supply rails, cells are flipped in alternating rows. To -avoid any extra routing, the power/ground rails, bitlines, and -wordlines should span the entire width/height of the cell so thay they -are automatically connected when the cells are abutted. +The bitcell class in \verb|modules/bitcell.py| is a single +memory cell and is usually a pre-made library cell. + +% bitcell_array +The bitcell\_array class in \verb|modules/bitcell_array.py| dynamically +implements the memory cell array by instantiating a the bitcell class +in rows and columns. + +% abutment connections +During the tiling process, bitcells are abutted so that all bitlines +and word lines are connected in the vertical and horizontal directions +respectively. This is done by using the boundary layer to define the +height and width of the cell. If this is not specified, OpenRAM will +use the bounding box of all shapes as the boundary. The boundary layer +should be offset at (0,0) in the lower left coordinate. + +% flipping +In order to share supply rails, bitcells are flipped in alternating +rows. + \subsection{Precharge Circuitry} @@ -109,103 +102,83 @@ are automatically connected when the cells are abutted. The precharge circuit is depicted in Figure~\ref{fig:precharge} and is implemented by three PMOS transistors. The input signal to the cell, clk, enables all three transistors during the first half of a read or -write cycle (i.e. while the clock signal is low). M1 and M2 charge BL -and BLB to Vdd and M3 helps to equalize the voltages seen on BL and -BLB. +write cycle (i.e. while the clock signal is low). M1 and M2 charge bl +and br to vdd while M3 equalizes the voltages seen between the bitlines. \begin{figure}[h!] \centering \includegraphics[width=5cm]{./figs/precharge_schem.pdf} -\caption{Schematic of a single precharge cell. \fixme{Change PCLK to CLK.}} +\caption{Schematic of a precharge circuit.} \label{fig:precharge} \end{figure} In OpenRAM, the precharge citcuitry is dynamically generated using the -parameterized transistor class (\verb|ptx|). The \verb|precharge| -class in \verb|precharge.py| dynamically generates a single precharge cell. +parameterized transistor class ptx which is further discussed in +Section~\ref{sec:ptx}. The offsets of the bitlines and the width of +the precharge cell are equal to the bitcell so that the bitlines are +correctly connected by abutment. The precharge class in +\verb|modules/precharge.py| dynamically generates a single precharge +cell. + +\verb|modules/precharge_array.py| creates a row of precharge cells at +the top of a bitcell array. + -The offsets of the bitlines and the width of the precharge cell are -equal to the 6T cell so that the bitlines are correctly connected down -to the 6T cell. The \verb|precharge_array| class is then used to -generate a precharge array, which is a single row of \textbf{n} -precharge cells, where \textbf{n} equals the number of columns in the -bitcell array. \subsection{Address Decoders} -\label{sec:addressdecoder} +\label{sec:address_decoder} -The address decoder takes the row address bits from the address bus as -inputs, and asserts the appropriate wordline in the row that data is -to be read or written. A n-bit address input controls $2^n$ word -lines. +The address decoder deodes the binary-encoded row address bits from the +address bus as inputs, and asserts a one-hot wordline in the row that +data is to be read or written. OpenRAM provides a hierarchical address +decoder as the default, but will soon have other options. -OpenRAM provides a hierarchical address decoder as the default, but -will soon have other options. +The address decoders are created using parameterized gates (pnand2, +pnand3, pinv) and transistors (ptx). This means that the decoders do +not rely on any hard library cells. \subsubsection{Hierarchical Decoder} \label{sec:hierdecoder} -Hierarchical decoder is a type of decoder which the constrcution takes place hierarchically. -The simple 2:4 decoder is shown in the Figure~\ref{fig:2 to 4 decoder}. The operation of -this decoder can be explained as follows: soon after the address signals A0 and A1 are put on the address lines, -depending on the signal combination, one of the wordlines will rise after a brief amount of time. For example if the -address input is A0A1=00 then the output is W0W1W2W3=1000. The 2:4 address decoder uses inverters and two -input nand gates for its constrcution while the gates are sized to have equal rise and fall time. -As the decoder size increases the size of the nand gates required for decoding also increases. -Table~\ref{table:2-4 hierarchical_decoder} gives the detailed input and output siganls -for the 2:4 hierarchical decoder. + +A simple 2:4 decoder is shown in Figure~\ref{fig:2:4decoder}. This +decoder computes all of the possible decode values using a single +level of nand gates along with the inverted and non-inverted inputs. +As the decoder size increases the size of the nand gates required for +decoding would increase proportional to the bits to be decoded. This +would not be practical for large decoders. \begin{figure}[h!] \centering \includegraphics[scale=.6]{./figs/2t4decoder.pdf} \caption{Schematic of 2-4 simple decoder.} -\label{fig:2 to 4 decoder} +\label{fig:2:4decoder} \end{figure} - \begin{table}[h!] - \begin{center} - \begin{tabular}{| c | c |} - \hline - A[1:0] & Selected WL\\ \hline - 00 & 0\\ \hline - 01 & 1\\ \hline - 10 & 2\\ \hline - 11 & 3\\ \hline - - \end{tabular} - \end{center} - \caption{Truth table for 2:4 hierarchical decoder.} - \label{table:2-4 hierarchical_decoder} - \end{table} - - -An $n$-bit decoder requires {$2^n$} logic gates, each with $n$ inputs. For example, with $n$ = 6, -64 $NAND6$ gates are needed to drive 64 inverters to implement the decoder. -It is clear that gates with more than 3 inputs create large series resistances and long delays. -Rather than using $n$-input gates, it is preferable to use a cascade of gates. -Typically two stages are used: a predecode stage and a final decode stage. -The predecode stage generates intermediate signals that are used -by multiple gates in the final decode stage. - - +A hierarchical decoder uses two-levels of decoding hierarchy to +perform an address decode. The first stage computes predecoded values +while the second stage computes the final decoded values. +Figure~\ref{fig:4 to 16 decoder} shows a 4:16 heirarchical +decoder. The decoder uses two 2:4 decoders for +predecoding and 2-input nand gates and inverters for final decoding to +form the 4:16 decoder. \begin{figure}[h!] \centering \includegraphics[scale=.6]{./figs/4t16decoder.pdf} -\caption{Schematic of 4 to 16 hierarchical decoder.} +\caption{Schematic of 4:16 hierarchical decoder.} \label{fig:4 to 16 decoder} \end{figure} -Figure~\ref{fig:4 to 16 decoder} shows the 4 to 16 heirarchical decoder. The structure of the decoder consists of two 2:4 decoders for predecoding and 2-input nand gates and inverters for final decoding to form the 4:16 decoder. -In the predecoder, a total of 8 intermediate signals are generated from the address bits and their complements. -The concept of using predecoing and final decoding stage for construction of address decoder is very procutive since small -decoders like 2:4 decoder is used for predecoding. The operation of 4:16 heirarchical decoder can explained with an example. If the address is A0A1A2A3=0000 the output of the predecoder1 and predeocder2 will be -WL0WL1WL2WL3=1000 and WL0WL1WL2WL3=1000, respectively. According to the connections in figure~\ref{fig:4 to 16 decoder} the wordline 0 of predecoder1 and predecoder2 are conneted -to the first 2-input nand gate in the decode stage representing the wordline 0 of the final decoding stage. Hence depengin on the combination -of the input signal one of the wordline will rise. In this case since the address input is A0A1A2A3=0000 the wordline 0 should go high. Table~\ref{table:4-16 hierarchical_decoder} gives the detailed input and output siganls -for the 4:16 hierarchical decoder. +The predecoder generates a total of 8 intermediate signals from the +address bits and their complements. These intermediate signals are in +two groups of 4 from each decoder. The enumeration of all 4 x 4 +predecoded values are used by the final decode to produce the 16 +decoded results. As an example, Table~\ref{table:4-16 hierarchical_decoder} +gives the detailed input and output siganls for the 4:16 hierarchical +decoder. \begin{table}[h!] @@ -236,152 +209,188 @@ for the 4:16 hierarchical decoder. \end{table} -As the size of the address line increases higher level decoder can be created using the lower level decoders. For example for a 8:256 decoder, two instances of 4:16 followed by 256 2-input nand gates and inverters -can form the decoder. In order to construct the 8:256 decoder, first 4:16 decoder should be constructed through using 2:4 deccoders. Hence the name is hierarchical decoder. +As the address size increases, additional sizes of pre- and final +decoders can be used. In OpenRAM, there are implementations for +\verb|modules/hierarchical\_predecode2x4.py| and +\verb|modules/hierarchical\_predecode3x8.py| to produce 2:4 and 3:8 +predecodes, respectively. These same decoders are used to generate the +column mux select bits as well. + +For the final decode, we can use either pnand2 or pnand3 gates. This +allows a maximum size of three 3:8 predocers along with a final pnand3 decode +stage, or, 512 word lines. To extend beyond this, a pnand4 or +a 4:16 predecoder would be needed. \subsection{Wordline Driver} \label{sec:wldriver} -Word line drivers are inserted, in between the word line -output of the address decoder and the word line input of the bitcell-array. The word -line drivers ensure that as the size of the memory array increases, -and the word line length and capacitance increases, the word line -signal is able to turn on the access transistors in the 6T cell. Also, as the bank select signal -in multi-bank structures is $ANDED$ with the word line output of decoder, -bitcells turn on only when bank is selected. -Figure~\ref{fig:wordline_driver} shows the diagram of word line driver and its input/output pins. -In OpenRAM, word line drivers are created by using the \verb|pinv| and \verb|nand2| classes which -takes the transistor size and cell height as inputs (so that it can abutt the -6T cell). Word line driver is added as seperate module in \verb|compiler|. +The word line driver buffers the address decoder to drive the wordline and +gates the signal until the decode has stabilized. Without waiting, an +incorrectly asserted wordline could erase memory contents. +The word line driver is sized according to the bitcell array width so +that wordlines in larger memory arrays can be appropriately driven. + +% gating for first half decode, second half read/write +The first half of the clock cycle is used for address decoding in +OpenRAM. Therefore, the wordline driver is enabled in the second half +of the clock cycle in OpenRAM. The buffered clock signal drives each +wordline driver row and is logically ANDed with the decoder output. + +% bank clock gating for wordline driver +In multi-bank structures the clock buffer is also anded with the bank +select signal to prevent the read/writing of an entire bank. + \begin{figure}[h!] \centering -\includegraphics[scale=.8]{./figs/wordline_driver.pdf} +\includegraphics[scale=.6]{./figs/wordline_driver.pdf} \caption{Diagram of word line driver.} \label{fig:wordline_driver} \end{figure} +Figure~\ref{fig:wordline_driver} illustrates the wordline driver and +its inputs/outputs. This is implemented in the +\verb|modules/wordline_driver.py| module and matches the number of +rows in the bitcell array of a bank. + +OpenRAM creates the wordline drivers using the parameterized pinv and +pnand2 classes. This enables the wordline driver to be matched to the +bitcell height and to sized to drive the wordline load. + + \subsection{Column Mux} +\label{sec:column_mux} +The column mux is an optional module in an SRAM bank. Without a column +mux, the bank is assumed to have a single word in each row. A column +mux enables more more than one word to be stored in each row and +read/written individually. The column mux is used for both the read +and write operations by connecting the bitlines of a bank to +both the sense amplifier and the write driver. -The column mux takes the column address bits from the address bus -selects the appropriate bitlines for the word that is to be read from -or written to. It takes n-bits from the address bus and can select -$2^n$ bitlines. The column mux is used for both the read and write -operations; it connects the bitline of the memory array to both the -sense ampflifier and the write driver. +In OpenRAM, the column mux uses the {\bf high address bits} to select +the appropriate word in each row. If n-bits are used, there are $2^n$ +words in each row. OpenRAM currently allows 2, 4, or 8 words per row, +but the 8 words are not fully debugged (as of 2/12/18). -OpenRAM provides several options for column mux, but the default -is a single-level column mux which is sized for optimal speed. +%% OpenRAM provides several options for column mux, but the default +%% is a single-level column mux which is sized for optimal speed. -\subsubsection{Tree\_Decoding Column Mux} -\label{sec:tree_decoding_column_mux} +%% \subsubsection{Tree\_Decoding Column Mux} +%% \label{sec:tree_decoding_column_mux} -The schematic for a 4-1 tree -multiplexer is shown in Figure~\ref{fig:colmux}. +%% The schematic for a 4-1 tree +%% multiplexer is shown in Figure~\ref{fig:colmux}. -\begin{figure}[h!] -\centering -\includegraphics[scale=.9]{./figs/tree_column_mux_schem.pdf} -\caption{Schematic of 4-1 tree column mux that passes both of the bitlines.} -\label{fig:colmux} -\end{figure} +%% \begin{figure}[h!] +%% \centering +%% \includegraphics[scale=.9]{./figs/tree_column_mux_schem.pdf} +%% \caption{Schematic of 4-1 tree column mux that passes both of the bitlines.} +%% \label{fig:colmux} +%% \end{figure} -\fixme{Shading/opacity is different on different platforms. Make this a box in the image. It doesn't work on OSX.} +%% \fixme{Shading/opacity is different on different platforms. Make this a box in the image. It doesn't work on OSX.} -This tree mux selects pairs of bitlines (both BL and BL\_B) as inputs -and outputs. This 4-1 tree mux illustrates the process of choosing -the correct bitlines if there are 4 words per row in the memory array. -Each bitline pair represents a single bit from each word. A binary -reduction pattern, shown in Table~\ref{table:colmux}, is used to -select the appropriate bitlines. As the number of words per row in -the memory array increases, the depth of the column mux grows. The -depth of the column mux is equal to the number of bits in the column -address bus. The 4-1 tree mux has a depth of 2. In level 1, the -least significant bit from the column address bus selects either the -first and second words or the third and fourth words. In level 2, the -most signifant column address bit selects one of the words passed down -from the previous level. Relative to other column mux designs, the -tree mus uses significantly less devices. But, this type of design -can provide poor performance if a large decoder with many levels are -needed. The delay of of a tree mux quadratically increases with each -level. Due to this fact, other types of column -decoders should be considered for larger arrays. +%% This tree mux selects pairs of bitlines (both BL and BL\_B) as inputs +%% and outputs. This 4-1 tree mux illustrates the process of choosing +%% the correct bitlines if there are 4 words per row in the memory array. +%% Each bitline pair represents a single bit from each word. A binary +%% reduction pattern, shown in Table~\ref{table:colmux}, is used to +%% select the appropriate bitlines. As the number of words per row in +%% the memory array increases, the depth of the column mux grows. The +%% depth of the column mux is equal to the number of bits in the column +%% address bus. The 4-1 tree mux has a depth of 2. In level 1, the +%% least significant bit from the column address bus selects either the +%% first and second words or the third and fourth words. In level 2, the +%% most signifant column address bit selects one of the words passed down +%% from the previous level. Relative to other column mux designs, the +%% tree mus uses significantly less devices. But, this type of design +%% can provide poor performance if a large decoder with many levels are +%% needed. The delay of of a tree mux quadratically increases with each +%% level. Due to this fact, other types of column +%% decoders should be considered for larger arrays. -\begin{table}[h!] - \begin{center} - \begin{tabular}{| c | c | c | c |} - \hline - Selected BL & Inp1 & Inp2 & Binary\\ \hline - BL0 & SEL0\_bar & SEL1\_bar & 00\\ \hline - BL1 & SEL0 & SEL1\_bar & 01\\ \hline - BL2 & SEL0\_bar & SEL1 & 10\\ \hline - BL3 & SEL0 & SEL1 & 11\\ - \hline - \end{tabular} - \end{center} - \caption{Binary reduction pattern for 4-1 tree column mux.} - \label{table:colmux} -\end{table} +%% \begin{table}[h!] +%% \begin{center} +%% \begin{tabular}{| c | c | c | c |} +%% \hline +%% Selected BL & Inp1 & Inp2 & Binary\\ \hline +%% BL0 & SEL0\_bar & SEL1\_bar & 00\\ \hline +%% BL1 & SEL0 & SEL1\_bar & 01\\ \hline +%% BL2 & SEL0\_bar & SEL1 & 10\\ \hline +%% BL3 & SEL0 & SEL1 & 11\\ +%% \hline +%% \end{tabular} +%% \end{center} +%% \caption{Binary reduction pattern for 4-1 tree column mux.} +%% \label{table:colmux} +%% \end{table} -In OpenRAM, the tree column mux is a dynamically generated design. The -\verb|tree_mux_array| is made up of two dynamically generated cells: \verb|muxa| -and \verb|mux_abar|. The only diffference between these cells is that input -select signal is either hooked up to the \textbf{SEL} or -\textbf{SEL\_bar} signals (see highlighted boxes in -Figure~\ref{fig:colmux}). These cells are initialized the the -\verb|column_muxa| and \verb|column_muxabar| classes in \verb|columm_mux.py|. Instances -of \verb|ptx| PMOS transistors are added to the design and the necessary -routing is performed using the \verb|add_rect()| function. A horizontal rail -is added in metal2 for both the SEL and Sel\_bar signals. Underneath -those input rails, horizontal straps are added. These straps are used -to connect the BL and BL\_B outputs from \verb|muxa| to the BL and BL\_B -outputs of \verb|mux_abar|. Vertical conenctors in metal3 are added at the -bottom of the cell so that connections can be made down to the sense -amp. Vertical connectors are also added in metal1 so that the cells -can connect down to other mux cells when the depth of the tree mux is -more than one level. +%% In OpenRAM, the tree column mux is a dynamically generated design. The +%% \verb|tree_mux_array| is made up of two dynamically generated cells: \verb|muxa| +%% and \verb|mux_abar|. The only diffference between these cells is that input +%% select signal is either hooked up to the \textbf{SEL} or +%% \textbf{SEL\_bar} signals (see highlighted boxes in +%% Figure~\ref{fig:colmux}). These cells are initialized the the +%% \verb|column_muxa| and \verb|column_muxabar| classes in \verb|columm_mux.py|. Instances +%% of \verb|ptx| PMOS transistors are added to the design and the necessary +%% routing is performed using the \verb|add_rect()| function. A horizontal rail +%% is added in metal2 for both the SEL and Sel\_bar signals. Underneath +%% those input rails, horizontal straps are added. These straps are used +%% to connect the BL and BL\_B outputs from \verb|muxa| to the BL and BL\_B +%% outputs of \verb|mux_abar|. Vertical conenctors in metal3 are added at the +%% bottom of the cell so that connections can be made down to the sense +%% amp. Vertical connectors are also added in metal1 so that the cells +%% can connect down to other mux cells when the depth of the tree mux is +%% more than one level. -The \verb|tree_mux_array| class is used to generate the tree mux. -Instances of both the \verb|muxa| and \verb|mux_abar| cells are instantiated and -are tiled row by row. The offset of the cell in a row is determined -by the depth of that row in the tree mux. The pattern used to -determine the offset of the mux cells is -$muxa.width*(i)*(2*row\_depth)$ where is the column number. As the -depth increases, the mux cells become further apart. A separate -``for'' loop is invoked if the $depth>1$, which extends the -power/ground and select rails across the entire width of the array. -Similarly, if the $depth>1$, spice net names are created for the -intermediate connection made at the various levels. This is necessary -to ensure that a correct spice netlist is generated and that the -input/output pins of the column mux match the pins in the modules that -it is connected to. +%% The \verb|tree_mux_array| class is used to generate the tree mux. +%% Instances of both the \verb|muxa| and \verb|mux_abar| cells are instantiated and +%% are tiled row by row. The offset of the cell in a row is determined +%% by the depth of that row in the tree mux. The pattern used to +%% determine the offset of the mux cells is +%% $muxa.width*(i)*(2*row\_depth)$ where is the column number. As the +%% depth increases, the mux cells become further apart. A separate +%% ``for'' loop is invoked if the $depth>1$, which extends the +%% power/ground and select rails across the entire width of the array. +%% Similarly, if the $depth>1$, spice net names are created for the +%% intermediate connection made at the various levels. This is necessary +%% to ensure that a correct spice netlist is generated and that the +%% input/output pins of the column mux match the pins in the modules that +%% it is connected to. -\subsubsection{Single\_Level Column Mux} +\subsubsection{Single-Level Column Mux} \label{sec:single_level_column_mux} -The optimal design for column mux uses a single NMOS device, driven by the input address or decoded input addresses. -Figure~\ref{fig:2t1_single_level_column_mux} shows the schematic of a 2:1 single-level column mux. In this column mux one bit -of address and its complementry drive the pass transistors. Selected transistors will -connect their corresponding bitlines ( 1 set of column out of 2 set of columns) to sense-amp and write-driver circuitry for read or write operation. -Figure~\ref{fig:4t1_single_level_column_mux} shows the schematic of a 4:1 single-level column mux. In this column mux, 2 input -address are decoded using a 2:4 decoder ( 2:4 decoder is explain in section~\ref{sec:hierdecoder}). 2:4 decoder provides a one-hot set of outputs, so only one set of columns -will be selected and connected to sense-amp and write-driver -( in figure~\ref{fig:4t1_single_level_column_mux} one set of column out of four sets of column is selected). +OpenRAM includes a single-level pass-gate mux implemtation for the +column mux. A single level of NMOS devices is driven by either the +input address (and it's complement) or decoded input addresses using a +2:4 predecoder (Section~\ref{sec:hierdecoder}). -In OpenRAM, the \verb|single-level_mux_array| is a dynamically generated design and -it is made up of dynamically generated cell (\verb|single-level_mux|). -\verb|single-level_mux| uses the parameterized transistor class \verb|ptx| to generate two NMOS transistors -which will connect the BL and BLB of selected columns to sense-amp and write-driver. Horizontal rails are added for $sel$ signals. Vertical -straps connect the BL and BLB of bitcell\_array to BL and BLB of single-level column mux and also BL-out and BLB-out of single-level -column mux to BL and BLB of sense-amp and write-driver. +Figure~\ref{fig:2t1_single_level_column_mux} shows the schematic of a +2:1 single-level column mux. In this column mux, the {\bf MSB of the + address bus} and it's complement drive the pass transistors. + +Figure~\ref{fig:4t1_single_level_column_mux} shows the schematic of a +4:1 single-level column mux. The select bits are decoded from the {\bf + 2 MSB of the address bus} using a 2:4 decoder. The 2:4 decoder +provides one-hot select signals to select one column. + +In OpenRAM, one mux, single\_level\_mux, is dynamically generated in +\verb|modules/single_level_column_mux.py| and multiple of these muxes +are tiled together in \verb|modules/single_level_column_mux_array.py|. + +single\_level\_mux uses the parameterized ptx (Section~\ref{sec:ptx} +to generate 2 or 4 NMOS transistors for each the bl and br +bitlines. Horizontal rails are added for the $sel$ signals. The +bitlines are automatically pitch-matched to the bitcell array. \begin{figure}[h!] \centering -\includegraphics[scale=.7]{./figs/2t1_single_level_column_mux.pdf} -\caption{Schematic of a 2:1 single level column mux.} +\includegraphics[scale=.5]{./figs/2t1_single_level_column_mux.pdf} +\caption{Schematic of a 2:1 single level column mux. \fixme{Signals names are wrong.}} \label{fig:2t1_single_level_column_mux} \end{figure} @@ -389,8 +398,8 @@ column mux to BL and BLB of sense-amp and write-driver. \begin{figure}[h!] \centering -\includegraphics[scale=.6]{./figs/4t1_single_level_column_mux.pdf} -\caption{Schematic of a 4:1 single level column mux.} +\includegraphics[scale=.5]{./figs/4t1_single_level_column_mux.pdf} +\caption{Schematic of a 4:1 single level column mux. \fixme{Signals names are wrong.}} \label{fig:4t1_single_level_column_mux} \end{figure} @@ -398,13 +407,10 @@ column mux to BL and BLB of sense-amp and write-driver. \subsection{Sense Amplifier} \label{sec:senseamp} The sense amplifier is used to sense the difference between the -bitline and bitline bar while a read operation is performed. The -sense amp is necessary to recover the signals from the bitlines -because they do not experience full voltage swing. As the size of the -memory array grows, the load of the bitlines increases and the voltage -swing is limited by the small memory cell driving this large load. A -differential sense amplifier is used to``sense'' the small voltage -difference between the bitlines. +bitline and bitline bar while a read operation is performed. +The sense amplifier also includes two PMOS transistors for bitline +isolation to speed-up read operations. The schematic for the sense amp is shown in +Figure~\ref{fig:sense_amp}. \begin{figure}[h!] \centering @@ -413,33 +419,47 @@ difference between the bitlines. \label{fig:sense_amp} \end{figure} -The schematic for the sense amp is shown in -Figure~\ref{fig:sense_amp}. The sense amplifier is enable by the SCLK -signal, which initiates the read operation. Before the sense -amplifier is enable, the bitlines are precharged to Vdd by the -precharge unit. When the sense amp is enabled, one of the bitlines -experiences a voltage drop based on the value stored in the memory -cell. If a zero is stored, the bitline voltage drops. If a one is -stored, the bitline bar voltage drops. The output signal is then +During address decoding (while the wordline is not asserted), the sense +amplifier is disabled and the bitlines are precharged to vdd by the +precharge unit. The two PMOS transistors also connect the bitlines to the sense amplifier. + +The en signal comes from the control logic (Section~\ref{sec:control}) +including the timing and replica bitline (Section~\ref{sec:RBL}). It +is only enabled after sufficient swing is seen on the bitlines so that +the value can be accurately sensed. + +The sense amplifier is enabled by the en signal, which initiates the +read operation, and also isolates the sense amplifier from the +bitlines. This allows the sense amplifier to drive a smaller +capacitance rather than the whole bitline. At this time, the footer +transistor is also enabled which allows the sense amplifier to use +feedback to sense the bitline differential voltage. + +When the sense amp is enabled, one of the bitlines experiences a +voltage drop based on the value stored in the memory cell. If a zero +is stored, the bitline voltage drops. If a one is stored, the bitline +bar voltage drops. The output signal is then taken to a true logic level and latched for output to the data bus. In OpenRAM, the sense amplifier is a libray cell. The associated -layout and spice netlist can be found in the \verb|gds_lib| and \verb|sp_lib| in -the FreePDK45 directory. The \verb|sense_amp| class in \verb|sense_amp.py| -instantiates a single instance of the sense amp library cell. The -\verb|sense_amp_array| class handles the tiling of the sense amps cells. -One sense amp cell is needed per data bit and the sense amp cells need -to be appropriately spaced so that they can hook up to the column mux -bitline pairs. The spacing is determined based on the number of words -per row in the memory array. Instances are added and then Vdd, Gnd -and SCLK rails that span the entire width of the array are drawn using -the add\_rect() function. +layout and spice netlist can be found in the \verb|gds_lib| and +\verb|sp_lib| in the technology directory. The sense\_amp class in +\verb|modules/sense_amp.py| is a single instance of the sense amp +library cell. -We chose to leave the sense amp as a libray cell so that custom + +The sense\_amp\_array class in \verb|modules/sense_amp_array.py| +handles the tiling of the sense amps cells. One sense amp cell is +needed per data bit and the sense amp cells need to be appropriately +spaced so that they can hook up to the column mux bitline pairs. The +spacing is determined based on the number of words per row in the +memory array. + +The sense amp is a library cell so that custom amplifier designs could be swapped into the memory as needed. The two major things that need to be considered while designing the sense amplifier cell are the size of the cell and the bitline/input pitches. -Optimally, the cell should be no larger than the 6T cell so that it +Optimally, the cell should be no wider than the 6T cell so that it abuts to the column mux and no extra routing or space is needed. Also, the bitline inputs of the sense amp need to line up with the outputs of the write driver. In the current version of OpenRAM, the @@ -451,6 +471,7 @@ connect the write driver to the column mux without any extra routing. \subsection{Write Driver} \label{sec:writedriver} + The write driver is used to drive the input signal into the memory cell during a write operation. It can be seen in Figure~\ref{fig:write_driver} that the write driver consists of two diff --git a/docs/openram_manual.pdf b/docs/openram_manual.pdf index 18521195..3a42e6b9 100644 Binary files a/docs/openram_manual.pdf and b/docs/openram_manual.pdf differ diff --git a/docs/openram_manual.tex b/docs/openram_manual.tex index 1ac0fc97..32dfc3be 100644 --- a/docs/openram_manual.tex +++ b/docs/openram_manual.tex @@ -25,7 +25,6 @@ \title{OpenRAM Manual} \author{Matthew R. Guthaus - mrg@ucsc.edu\\ - James Stine - james.stine@okstate.edu\\ and many others } %\renewcommand{\today}{October 14, 2010} diff --git a/docs/overview.tex b/docs/overview.tex index c5f36370..89378c80 100644 --- a/docs/overview.tex +++ b/docs/overview.tex @@ -49,9 +49,11 @@ The inputs to the SRAM are: \item CSb - Active-low Chip Select \item WEb - Active-low Write Enable \item OEb - Active-low Output Enable -\item ADDR\# - corresponds to the Address Bus input, labeled 0 to N-address bits. -\item DATA\# - corresponds to the bi-directional Data bus. +\item ADDR[\#] - Address Bus input (LSB is 0) +\item DATA[\#] - Bi-directional Data bus (LBS is 0) \end{itemize} +If multiple ports are used, the ADDR and DATA buses are appended with +integers to extend them. The outputs to the SRAM are: \begin{itemize} @@ -59,33 +61,30 @@ The outputs to the SRAM are: \item DATA\# - correspond to the bi-directional Data bus. \end{itemize} +The supply voltages to the SRAM are: +\begin{itemize} +\item vdd - Supply voltage +\item gnd - Ground supply voltage +\end{itemize} \subsection{Top-Level SRAM Module} \label{sec:sram} -The \verb|sram| class in \verb|sram.py| is the top-level SRAM module. -This class handles the overall organization of the memory and the -input/output signals. Based on the user inputs, the various bus and -array sizes are calculated and passed to the \verb|bank| module. -All other sub-modules access the value of sizes from \verb|bank|. -The overall organization is depicted in -Figure~\ref{fig:sram_architecture}, discussion of the design data -structure is discussed in Section~\ref{sec:design} and the modules -contained in the top-level SRAM are detailed in -Section~\ref{sec:modules}. - -When the user has specified the desired size (word size, total -number of words and number of banks) of the memory that is to be generated, -the following parameters must be calculated. There are several constraints -to be considered in this calculations: - -(i) \verb|sram| can generate 1 bank, 2 banks or 4 banks. - -(ii) The area of each bank should be as square as possible which is dependent on the area of a 6T cell. - -(iii) There are several options for multiplexing (column-mux): 2-way, 4-way, 8-way and none. +The sram class in \verb|sram.py| is the top-level SRAM module. This +class handles the overall organization of the memory, instantiates the +contorl logic, instantiates a number of banks, and creates decoded +enable signals for multiple banks. All of the top level routing is +performed in the sram class. -All of the top level routing is performed in the \verb|sram| class. +The sram class instantiates identical copies of the bank module from +\verb|bank.py|. All other sub-modules access the value of sizes from +bank. The bank module includes an address decoder, (optional) column +address decoder, (optional) column mux, sense amplifiers, precharge +circuitry, write drivers, etc. A single bank organization is depicted +in Figure~\ref{fig:sram_architecture}. + +Discussion of the design data structure is discussed in +Section~\ref{sec:design} and the modules contained in the top-level +SRAM are detailed in Section~\ref{sec:modules}. -\fixme{More soon...} diff --git a/docs/parameterized.tex b/docs/parameterized.tex index bcd89871..e85670bb 100644 --- a/docs/parameterized.tex +++ b/docs/parameterized.tex @@ -126,7 +126,7 @@ height=tech.cell_6t["height"]) \begin{figure}[h!] \centering -\includegraphics[width=10cm]{./figs/nand2.pdf} +%\includegraphics[width=10cm]{./figs/nand2.pdf} \caption{An example of Parameterized NAND2(nand\_2)} \label{fig:nand2} \end{figure} @@ -169,7 +169,7 @@ height=tech.cell_6t["height"]) \begin{figure}[h!] \centering -\includegraphics[width=10cm]{./figs/nand3.pdf} +%\includegraphics[width=10cm]{./figs/nand3.pdf} \caption{An example of Parameterized NAND3(nand\_3)} \label{fig:nand3} \end{figure} diff --git a/docs/timing.tex b/docs/timing.tex index d022d208..7cf0f6d2 100644 --- a/docs/timing.tex +++ b/docs/timing.tex @@ -10,7 +10,7 @@ Top-Level Signals: \setlength{\itemsep}{0pt} \item ADDR - address bus. \item DATA - bi-directional data bus. -\item CLK - the global clock. +\item clk - the global clock. \item OEb - active low output enable. \item CSb - active low chip select. \item WEb - active low write enable. @@ -34,7 +34,7 @@ The main timing considerations for an SRAM are: \item Setup Time - time an input needs to be stable before the positive/negative clock edge. \item Hold Time - time an input needs to stay valid after the positive/negative clock edge. \item Minimun Cycle Time - time inbetween subsequent memory operations. -\item Memory Read Time - time from positive clock edge until valid data appears on the data bus. +\item Memory Read Time - time from negative clock edge until valid data appears on the data bus. \item Memory Write Time - time from negative clock edge until data has been driven into a memory cell. \end{itemize} @@ -66,9 +66,9 @@ Read Operation: \end{enumerate} \item On the falling edge of the clock (CLK): \begin{enumerate} - \item Word line has been asserted, the value stored in the memory cells pulls down one of the bitlines (BL if a 0 is stored, BL\_bar if a 1 is stored). + \item Word line is driven onto the bitlines, the value stored in the memory cells pulls down one of the bitlines (bl if a 0 is stored, br if a 1 is stored). \item s\_en enables the sense amplifier which senses the voltage difference of the bit lines, produces the output and keeps the value in its latch circuitry. - \item Tri-gate enables and put the output data on data bus. Data remains valid on the data bus for a complete clock cycle. + \item Tri-gate drives (tri\_en and tri\_en\_bar) the output data on data bus. Data remains valid on the data bus for a complete clock cycle. \end{enumerate} \end{enumerate} diff --git a/lib/Makefile b/lib/Makefile new file mode 100644 index 00000000..dcbab0a4 --- /dev/null +++ b/lib/Makefile @@ -0,0 +1,14 @@ +SUBDIRS := $(wildcard */.) +SUBDIRSCLEAN=$(addsuffix clean,$(SUBDIRS)) + +all: $(SUBDIRS) + +$(SUBDIRS): + $(MAKE) -C $@ + +clean: + for dir in $(SUBDIRS); do \ + $(MAKE) -C $$dir $@; \ + done + +.PHONY: all $(SUBDIRS) $(SUBDIRSCLEAN) diff --git a/lib/freepdk45/Makefile b/lib/freepdk45/Makefile new file mode 100644 index 00000000..9f441bb4 --- /dev/null +++ b/lib/freepdk45/Makefile @@ -0,0 +1,30 @@ +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 +%.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_1rw_128b_1024w_1bank_freepdk45.py b/lib/freepdk45/configs/sram_1rw_128b_1024w_1bank_freepdk45.py new file mode 100644 index 00000000..2a84bf8e --- /dev/null +++ b/lib/freepdk45/configs/sram_1rw_128b_1024w_1bank_freepdk45.py @@ -0,0 +1,5 @@ +word_size = 128 +num_words = 1024 +num_banks = 1 + +tech_name = "freepdk45" diff --git a/lib/freepdk45/configs/sram_1rw_32b_1024w_1bank_freepdk45.py b/lib/freepdk45/configs/sram_1rw_32b_1024w_1bank_freepdk45.py new file mode 100644 index 00000000..8ecdfef8 --- /dev/null +++ b/lib/freepdk45/configs/sram_1rw_32b_1024w_1bank_freepdk45.py @@ -0,0 +1,5 @@ +word_size = 32 +num_words = 1024 +num_banks = 1 + +tech_name = "freepdk45" diff --git a/lib/freepdk45/configs/sram_1rw_32b_2048w_1bank_freepdk45.py b/lib/freepdk45/configs/sram_1rw_32b_2048w_1bank_freepdk45.py new file mode 100644 index 00000000..b18dbca6 --- /dev/null +++ b/lib/freepdk45/configs/sram_1rw_32b_2048w_1bank_freepdk45.py @@ -0,0 +1,5 @@ +word_size = 32 +num_words = 2048 +num_banks = 1 + +tech_name = "freepdk45" diff --git a/lib/freepdk45/configs/sram_1rw_8b_1024w_4bank_freepdk45.py b/lib/freepdk45/configs/sram_1rw_8b_1024w_4bank_freepdk45.py new file mode 100644 index 00000000..e15b7c3d --- /dev/null +++ b/lib/freepdk45/configs/sram_1rw_8b_1024w_4bank_freepdk45.py @@ -0,0 +1,5 @@ +word_size = 8 +num_words = 1024 +num_banks = 4 + +tech_name = "freepdk45" diff --git a/lib/freepdk45/configs/sram_1rw_8b_256w_1bank_freepdk45.py b/lib/freepdk45/configs/sram_1rw_8b_256w_1bank_freepdk45.py new file mode 100644 index 00000000..f1962d9f --- /dev/null +++ b/lib/freepdk45/configs/sram_1rw_8b_256w_1bank_freepdk45.py @@ -0,0 +1,5 @@ +word_size = 8 +num_words = 256 +num_banks = 1 + +tech_name = "freepdk45" diff --git a/lib/freepdk45/configs/sram_1rw_8b_512w_4bank_freepdk45.py b/lib/freepdk45/configs/sram_1rw_8b_512w_4bank_freepdk45.py new file mode 100644 index 00000000..daeb9c8f --- /dev/null +++ b/lib/freepdk45/configs/sram_1rw_8b_512w_4bank_freepdk45.py @@ -0,0 +1,5 @@ +word_size = 8 +num_words = 512 +num_banks = 4 + +tech_name = "freepdk45" diff --git a/lib/scn3me_subm/Makefile b/lib/scn3me_subm/Makefile new file mode 100644 index 00000000..9f441bb4 --- /dev/null +++ b/lib/scn3me_subm/Makefile @@ -0,0 +1,30 @@ +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 +%.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/scn3me_subm/configs/sram_1rw_128b_1024w_1bank_scn3me_subm.py b/lib/scn3me_subm/configs/sram_1rw_128b_1024w_1bank_scn3me_subm.py new file mode 100644 index 00000000..b26c9c57 --- /dev/null +++ b/lib/scn3me_subm/configs/sram_1rw_128b_1024w_1bank_scn3me_subm.py @@ -0,0 +1,5 @@ +word_size = 128 +num_words = 1024 +num_banks = 1 + +tech_name = "scn3me_subm" diff --git a/lib/scn3me_subm/configs/sram_1rw_32b_1024w_1bank_scn3me_subm.py b/lib/scn3me_subm/configs/sram_1rw_32b_1024w_1bank_scn3me_subm.py new file mode 100644 index 00000000..07bf98a0 --- /dev/null +++ b/lib/scn3me_subm/configs/sram_1rw_32b_1024w_1bank_scn3me_subm.py @@ -0,0 +1,5 @@ +word_size = 32 +num_words = 1024 +num_banks = 1 + +tech_name = "scn3me_subm" diff --git a/lib/scn3me_subm/configs/sram_1rw_32b_2048w_1bank_scn3me_subm.py b/lib/scn3me_subm/configs/sram_1rw_32b_2048w_1bank_scn3me_subm.py new file mode 100644 index 00000000..28520ad9 --- /dev/null +++ b/lib/scn3me_subm/configs/sram_1rw_32b_2048w_1bank_scn3me_subm.py @@ -0,0 +1,5 @@ +word_size = 32 +num_words = 2048 +num_banks = 1 + +tech_name = "scn3me_subm" diff --git a/lib/scn3me_subm/configs/sram_1rw_8b_1024w_4bank_scn3me_subm.py b/lib/scn3me_subm/configs/sram_1rw_8b_1024w_4bank_scn3me_subm.py new file mode 100644 index 00000000..9752a6c6 --- /dev/null +++ b/lib/scn3me_subm/configs/sram_1rw_8b_1024w_4bank_scn3me_subm.py @@ -0,0 +1,5 @@ +word_size = 8 +num_words = 1024 +num_banks = 4 + +tech_name = "scn3me_subm" diff --git a/lib/scn3me_subm/configs/sram_1rw_8b_256w_1bank_scn3me_subm.py b/lib/scn3me_subm/configs/sram_1rw_8b_256w_1bank_scn3me_subm.py new file mode 100644 index 00000000..92e6027b --- /dev/null +++ b/lib/scn3me_subm/configs/sram_1rw_8b_256w_1bank_scn3me_subm.py @@ -0,0 +1,5 @@ +word_size = 8 +num_words = 256 +num_banks = 1 + +tech_name = "scn3me_subm" diff --git a/lib/scn3me_subm/configs/sram_1rw_8b_512w_4bank_scn3me_subm.py b/lib/scn3me_subm/configs/sram_1rw_8b_512w_4bank_scn3me_subm.py new file mode 100644 index 00000000..91990731 --- /dev/null +++ b/lib/scn3me_subm/configs/sram_1rw_8b_512w_4bank_scn3me_subm.py @@ -0,0 +1,5 @@ +word_size = 8 +num_words = 512 +num_banks = 4 + +tech_name = "scn3me_subm" diff --git a/technology/freepdk45/sp_lib/sense_amp.sp b/technology/freepdk45/sp_lib/sense_amp.sp index 112d96f9..b5778306 100644 --- a/technology/freepdk45/sp_lib/sense_amp.sp +++ b/technology/freepdk45/sp_lib/sense_amp.sp @@ -1,11 +1,11 @@ -.SUBCKT sense_amp bl br dout sclk vdd gnd +.SUBCKT sense_amp bl br dout en vdd gnd M_1 dout net_1 vdd vdd pmos_vtg w=540.0n l=50.0n M_3 net_1 dout vdd vdd pmos_vtg w=540.0n l=50.0n M_2 dout net_1 net_2 gnd nmos_vtg w=270.0n l=50.0n M_8 net_1 dout net_2 gnd nmos_vtg w=270.0n l=50.0n -M_5 bl sclk dout vdd pmos_vtg w=720.0n l=50.0n -M_6 br sclk net_1 vdd pmos_vtg w=720.0n l=50.0n -M_7 net_2 sclk gnd gnd nmos_vtg w=270.0n l=50.0n +M_5 bl en dout vdd pmos_vtg w=720.0n l=50.0n +M_6 br en net_1 vdd pmos_vtg w=720.0n l=50.0n +M_7 net_2 en gnd gnd nmos_vtg w=270.0n l=50.0n .ENDS sense_amp diff --git a/technology/freepdk45/tech/tech.py b/technology/freepdk45/tech/tech.py index 1947fcc7..dacc3644 100644 --- a/technology/freepdk45/tech/tech.py +++ b/technology/freepdk45/tech/tech.py @@ -237,35 +237,28 @@ drc["metal4_extend_via4"] = 0.07 spice = {} spice["nmos"] = "nmos_vtg" spice["pmos"] = "pmos_vtg" +# This is a map of corners to model files SPICE_MODEL_DIR=os.environ.get("SPICE_MODEL_DIR") -spice["fet_models"] = [SPICE_MODEL_DIR+"/NMOS_VTG.inc", - SPICE_MODEL_DIR+"/PMOS_VTG.inc"] +spice["fet_models"] = { "TT" : [SPICE_MODEL_DIR+"/models_nom/PMOS_VTG.inc",SPICE_MODEL_DIR+"/models_nom/NMOS_VTG.inc"], + "FF" : [SPICE_MODEL_DIR+"/models_ff/PMOS_VTG.inc",SPICE_MODEL_DIR+"/models_ff/NMOS_VTG.inc"], + "SF" : [SPICE_MODEL_DIR+"/models_ss/PMOS_VTG.inc",SPICE_MODEL_DIR+"/models_ff/NMOS_VTG.inc"], + "FS" : [SPICE_MODEL_DIR+"/models_ff/PMOS_VTG.inc",SPICE_MODEL_DIR+"/models_ss/NMOS_VTG.inc"], + "SS" : [SPICE_MODEL_DIR+"/models_ss/PMOS_VTG.inc",SPICE_MODEL_DIR+"/models_ss/NMOS_VTG.inc"]} #spice stimulus related variables -spice["feasible_period"] = 5 # estimated feasible period in ns -spice["supply_voltage"] = 1.0 #vdd in [Volts] -spice["gnd_voltage"] = 0.0 #gnd in [Volts] -spice["rise_time"] = 0.005 #rise time in [Nano-seconds] -spice["fall_time"] = 0.005 #fall time in [Nano-seconds] -spice["temp"] = 25 #temperature in [Celsius] - -#parasitics of metal for bit/word lines -spice["bitline_res"] = 0.1 #bitline resistance in [Ohms/micro-meter] -spice["bitline_cap"] = 0.2 #bitline capacitance in [Femto-farad/micro-meter] -spice["wordline_res"] = 0.1 #wordline resistance in [Ohms/micro-meter] -spice["wordline_cap"] = 0.2 #wordline capacitance in [Femto-farad/micro-meter] -spice["FF_in_cap"] = 0.2091 #Input capacitance of ms_flop (Din) [Femto-farad] -spice["tri_gate_out_cap"] = 0.41256 #Output capacitance of tri_gate (tri_out) [Femto-farad] - +spice["feasible_period"] = 5 # estimated feasible period in ns +spice["supply_voltages"] = [0.9, 1.0, 1.1] # Supply voltage corners in [Volts] +spice["rise_time"] = 0.005 # rise time in [Nano-seconds] +spice["fall_time"] = 0.005 # fall time in [Nano-seconds] +spice["temperatures"] = [0, 25, 100] # Temperature corners (celcius) #sram signal names +#FIXME: We don't use these everywhere... spice["vdd_name"] = "vdd" spice["gnd_name"] = "gnd" spice["control_signals"] = ["CSb", "WEb", "OEb"] spice["data_name"] = "DATA" spice["addr_name"] = "ADDR" -spice["pmos_name"] = spice["pmos"] -spice["nmos_name"] = spice["nmos"] spice["minwidth_tx"] = drc["minwidth_tx"] spice["channel"] = drc["minlength_channel"] spice["clk"] = "clk" @@ -280,6 +273,7 @@ spice["msflop_setup"] = 9 # DFF setup time in ps spice["msflop_hold"] = 1 # DFF hold time in ps spice["msflop_delay"] = 20.5 # DFF Clk-to-q delay in ps spice["msflop_slew"] = 13.1 # DFF output slew in ps w/ no load +spice["msflop_in_cap"] = 0.2091 # Input capacitance of ms_flop (Din) [Femto-farad] ################################################### diff --git a/technology/scn3me_subm/gds_lib/cell_6t.gds b/technology/scn3me_subm/gds_lib/cell_6t.gds index e7298cce..81c8112a 100644 Binary files a/technology/scn3me_subm/gds_lib/cell_6t.gds and b/technology/scn3me_subm/gds_lib/cell_6t.gds differ diff --git a/technology/scn3me_subm/gds_lib/replica_cell_6t.gds b/technology/scn3me_subm/gds_lib/replica_cell_6t.gds index 9f0f120d..50dd9d12 100644 Binary files a/technology/scn3me_subm/gds_lib/replica_cell_6t.gds and b/technology/scn3me_subm/gds_lib/replica_cell_6t.gds differ diff --git a/technology/scn3me_subm/mag_lib/cell_6t.mag b/technology/scn3me_subm/mag_lib/cell_6t.mag index eb8b8605..a0f2e63a 100644 --- a/technology/scn3me_subm/mag_lib/cell_6t.mag +++ b/technology/scn3me_subm/mag_lib/cell_6t.mag @@ -1,6 +1,6 @@ magic tech scmos -timestamp 1517421767 +timestamp 1517870584 << nwell >> rect -8 29 42 51 << pwell >> @@ -46,6 +46,7 @@ rect 12 36 16 40 rect 22 36 26 40 rect 32 36 36 40 << psubstratepcontact >> +rect -2 22 2 26 rect 32 22 36 26 << nsubstratencontact >> rect 32 44 36 48 @@ -77,7 +78,8 @@ rect -2 40 2 44 rect 32 40 36 44 rect 11 36 12 40 rect 26 36 27 40 -rect -2 16 2 29 +rect -2 26 2 29 +rect -2 16 2 22 rect 11 18 15 36 rect 23 24 27 36 rect 25 20 27 24 diff --git a/technology/scn3me_subm/mag_lib/replica_cell_6t.mag b/technology/scn3me_subm/mag_lib/replica_cell_6t.mag index 24d0aa8e..8257df55 100644 --- a/technology/scn3me_subm/mag_lib/replica_cell_6t.mag +++ b/technology/scn3me_subm/mag_lib/replica_cell_6t.mag @@ -1,6 +1,6 @@ magic tech scmos -timestamp 1517421800 +timestamp 1517870621 << nwell >> rect -8 29 42 51 << pwell >> @@ -46,6 +46,7 @@ rect 12 36 16 40 rect 22 36 26 40 rect 32 36 36 40 << psubstratepcontact >> +rect -2 22 2 26 rect 32 22 36 26 << nsubstratencontact >> rect 32 44 36 48 @@ -77,10 +78,11 @@ rect -2 40 2 44 rect 32 40 36 44 rect 11 36 12 40 rect 26 36 27 40 -rect -2 25 2 29 +rect -2 26 2 29 rect 11 25 15 36 -rect -2 21 15 25 +rect 2 22 15 25 rect 23 24 27 36 +rect -2 21 15 22 rect -2 16 2 21 rect 11 18 15 21 rect 25 20 27 24 diff --git a/technology/scn3me_subm/models/ff/nmos.sp b/technology/scn3me_subm/models/ff/nmos.sp new file mode 100644 index 00000000..70ffd267 --- /dev/null +++ b/technology/scn3me_subm/models/ff/nmos.sp @@ -0,0 +1,10 @@ +********************************************* +* Transistor Models +* Note: These models are approximate +* and should be substituted with actual +* models from MOSIS or SCN3ME +********************************************* + +.MODEL n NMOS (LEVEL=49 VTHO=0.669845 KP=113.7771E-6 ++ NSUB=6E16 U0=461 K1=0.5705 TOX=13.9n) + diff --git a/technology/scn3me_subm/models/ff/pmos.sp b/technology/scn3me_subm/models/ff/pmos.sp new file mode 100644 index 00000000..ee0d9691 --- /dev/null +++ b/technology/scn3me_subm/models/ff/pmos.sp @@ -0,0 +1,9 @@ +********************************************* +* Transistor Models +* Note: These models are approximate +* and should be substituted with actual +* models from MOSIS or SCN3ME +********************************************* + +.MODEL p PMOS (LEVEL=49 VTHO=-0.322431 KP=366.0244-6 ++ NSUB=6E16 U0=212 K1=0.0821 TOX=13.9n) diff --git a/technology/scn3me_subm/models/nom/nmos.sp b/technology/scn3me_subm/models/nom/nmos.sp new file mode 100644 index 00000000..d83289e8 --- /dev/null +++ b/technology/scn3me_subm/models/nom/nmos.sp @@ -0,0 +1,9 @@ +********************************************* +* Transistor Models +* Note: These models are approximate +* and should be substituted with actual +* models from MOSIS or SCN3ME +********************************************* + +.MODEL n NMOS (LEVEL=49 VTHO=0.669845 KP=113.7771E-6 ++ NSUB=6E16 U0=458 K1=0.5705 TOX=13.9n) diff --git a/technology/scn3me_subm/models/nom/pmos.sp b/technology/scn3me_subm/models/nom/pmos.sp new file mode 100644 index 00000000..ee0d9691 --- /dev/null +++ b/technology/scn3me_subm/models/nom/pmos.sp @@ -0,0 +1,9 @@ +********************************************* +* Transistor Models +* Note: These models are approximate +* and should be substituted with actual +* models from MOSIS or SCN3ME +********************************************* + +.MODEL p PMOS (LEVEL=49 VTHO=-0.322431 KP=366.0244-6 ++ NSUB=6E16 U0=212 K1=0.0821 TOX=13.9n) diff --git a/technology/scn3me_subm/models/ss/nmos.sp b/technology/scn3me_subm/models/ss/nmos.sp new file mode 100644 index 00000000..667667cd --- /dev/null +++ b/technology/scn3me_subm/models/ss/nmos.sp @@ -0,0 +1,10 @@ +********************************************* +* Transistor Models +* Note: These models are approximate +* and should be substituted with actual +* models from MOSIS or SCN3ME +********************************************* + +.MODEL n NMOS (LEVEL=49 VTHO=0.669845 KP=113.7771E-6 ++ NSUB=6E16 U0=460 K1=0.5705 TOX=13.9n) + diff --git a/technology/scn3me_subm/models/ss/pmos.sp b/technology/scn3me_subm/models/ss/pmos.sp new file mode 100644 index 00000000..ee0d9691 --- /dev/null +++ b/technology/scn3me_subm/models/ss/pmos.sp @@ -0,0 +1,9 @@ +********************************************* +* Transistor Models +* Note: These models are approximate +* and should be substituted with actual +* models from MOSIS or SCN3ME +********************************************* + +.MODEL p PMOS (LEVEL=49 VTHO=-0.322431 KP=366.0244-6 ++ NSUB=6E16 U0=212 K1=0.0821 TOX=13.9n) diff --git a/technology/scn3me_subm/sp_lib/sense_amp.sp b/technology/scn3me_subm/sp_lib/sense_amp.sp index 2d0ab02a..1399228d 100644 --- a/technology/scn3me_subm/sp_lib/sense_amp.sp +++ b/technology/scn3me_subm/sp_lib/sense_amp.sp @@ -1,12 +1,12 @@ *********************** "sense_amp" ****************************** -.SUBCKT sense_amp bl br dout sclk vdd gnd +.SUBCKT sense_amp bl br dout en vdd gnd M_1 dout net_1 vdd vdd p W='5.4*1u' L=0.6u M_2 dout net_1 net_2 gnd n W='2.7*1u' L=0.6u M_3 net_1 dout vdd vdd p W='5.4*1u' L=0.6u M_4 net_1 dout net_2 gnd n W='2.7*1u' L=0.6u -M_5 bl sclk dout vdd p W='7.2*1u' L=0.6u -M_6 br sclk net_1 vdd p W='7.2*1u' L=0.6u -M_7 net_2 sclk gnd gnd n W='2.7*1u' L=0.6u +M_5 bl en dout vdd p W='7.2*1u' L=0.6u +M_6 br en net_1 vdd p W='7.2*1u' L=0.6u +M_7 net_2 en gnd gnd n W='2.7*1u' L=0.6u .ENDS sense_amp diff --git a/technology/scn3me_subm/tech/tech.py b/technology/scn3me_subm/tech/tech.py index b797b81b..b8270578 100755 --- a/technology/scn3me_subm/tech/tech.py +++ b/technology/scn3me_subm/tech/tech.py @@ -76,7 +76,7 @@ drc["pwell_to_nwell"] = 0 drc["minwidth_well"] = 3.6 # 3.1 Minimum width drc["minwidth_poly"] = 0.6 -# 3.2/3.2.a Minimum spacing over field/active +# 3.2 Minimum spacing over active drc["poly_to_poly"] = 0.9 # 3.3 Minimum gate extension of active drc["poly_extend_active"] = 0.6 @@ -84,6 +84,8 @@ drc["poly_extend_active"] = 0.6 drc["poly_to_polycontact"] = 1.2 # ?? drc["active_enclosure_gate"] = 0.0 +# 3.2.a Minimum spacing over field poly +drc["poly_to_field_poly"] = 0.9 # 3.5 Minimum field poly to active drc["poly_to_active"] = 0.3 # Not a rule @@ -195,33 +197,31 @@ drc["minarea_metal3"] = 0 spice={} spice["nmos"]="n" spice["pmos"]="p" -spice["fet_models"] = [os.environ.get("SPICE_MODEL_DIR")+"/on_c5n.sp"] +# This is a map of corners to model files +SPICE_MODEL_DIR=os.environ.get("SPICE_MODEL_DIR") +# FIXME: Uncomment when we have the new spice models +#spice["fet_models"] = { "TT" : [SPICE_MODEL_DIR+"/nom/pmos.sp",SPICE_MODEL_DIR+"/nom/nmos.sp"] } +spice["fet_models"] = { "TT" : [SPICE_MODEL_DIR+"/nom/pmos.sp",SPICE_MODEL_DIR+"/nom/nmos.sp"], + "FF" : [SPICE_MODEL_DIR+"/ff/pmos.sp",SPICE_MODEL_DIR+"/ff/nmos.sp"], + "FS" : [SPICE_MODEL_DIR+"/ff/pmos.sp",SPICE_MODEL_DIR+"/ss/nmos.sp"], + "SF" : [SPICE_MODEL_DIR+"/ss/pmos.sp",SPICE_MODEL_DIR+"/ff/nmos.sp"], + "SS" : [SPICE_MODEL_DIR+"/ss/pmos.sp",SPICE_MODEL_DIR+"/ss/nmos.sp"] } + #spice stimulus related variables spice["feasible_period"] = 5 # estimated feasible period in ns -spice["supply_voltage"] = 5.0 #vdd in [Volts] -spice["gnd_voltage"] = 0.0 #gnd in [Volts] -spice["rise_time"] = 0.05 #rise time in [Nano-seconds] -spice["fall_time"] = 0.05 #fall time in [Nano-seconds] -spice["temp"] = 25 #temperature in [Celsius] - -#parasitics of metal for bit/word lines -spice["bitline_res"] = 0.1 #bitline resistance in [Ohms/micro-meter] -spice["bitline_cap"] = 0.2 #bitline capacitance in [Femto-farad/micro-meter] -spice["wordline_res"] = 0.1 #wordline resistance in [Ohms/micro-meter] -spice["wordline_cap"] = 0.2 #wordline capacitance in [Femto-farad/micro-meter] -spice["FF_in_cap"] = 9.8242 #Input capacitance of ms_flop (Din) [Femto-farad] -spice["tri_gate_out_cap"] = 1.4980 #Output capacitance of tri_gate (tri_out) [Femto-farad] - +spice["supply_voltages"] = [4.5, 5.0, 5.5] # Supply voltage corners in [Volts] +spice["rise_time"] = 0.05 # rise time in [Nano-seconds] +spice["fall_time"] = 0.05 # fall time in [Nano-seconds] +spice["temperatures"] = [0, 25, 100] # Temperature corners (celcius) #sram signal names +#FIXME: We don't use these everywhere... spice["vdd_name"] = "vdd" spice["gnd_name"] = "gnd" spice["control_signals"] = ["CSb", "WEb", "OEb"] spice["data_name"] = "DATA" spice["addr_name"] = "ADDR" -spice["pmos_name"] = spice["pmos"] -spice["nmos_name"] = spice["nmos"] spice["minwidth_tx"] = drc["minwidth_tx"] spice["channel"] = drc["minlength_channel"] spice["clk"] = "clk" @@ -237,6 +237,7 @@ spice["msflop_setup"] = 9 # DFF setup time in ps spice["msflop_hold"] = 1 # DFF hold time in ps spice["msflop_delay"] = 20.5 # DFF Clk-to-q delay in ps spice["msflop_slew"] = 13.1 # DFF output slew in ps w/ no load +spice["msflop_in_cap"] = 9.8242 # Input capacitance of ms_flop (Din) [Femto-farad] ################################################### diff --git a/technology/setup_scripts/setup_openram_freepdk45.py b/technology/setup_scripts/setup_openram_freepdk45.py index 7b40357e..35e819ee 100644 --- a/technology/setup_scripts/setup_openram_freepdk45.py +++ b/technology/setup_scripts/setup_openram_freepdk45.py @@ -29,9 +29,10 @@ except: os.environ["DRCLVS_HOME"] = DRCLVS_HOME # try: -# SPICE_MODEL_DIR = os.path.abspath(os.environ.get("SPICE_MODEL_DIR")) +# SPICE_MODEL_DIR = os.path.abspath(os.environ.get("SPICE_MODEL_DIR")) # except: -os.environ["SPICE_MODEL_DIR"] = PDK_DIR+"/ncsu_basekit/models/hspice/tran_models/models_nom" +# Always use the one in the PDK dir for FreePDK45 +os.environ["SPICE_MODEL_DIR"] = PDK_DIR+"/ncsu_basekit/models/hspice/tran_models" ########################## #Paths required for OPENRAM to function diff --git a/technology/setup_scripts/setup_openram_scn3me_subm.py b/technology/setup_scripts/setup_openram_scn3me_subm.py index fcc69db8..7fa4dbf9 100644 --- a/technology/setup_scripts/setup_openram_scn3me_subm.py +++ b/technology/setup_scripts/setup_openram_scn3me_subm.py @@ -27,10 +27,10 @@ except: DRCLVS_HOME=OPENRAM_TECH+"/scn3me_subm/tech" os.environ["DRCLVS_HOME"] = DRCLVS_HOME -try: - SPICE_MODEL_DIR = os.path.abspath(os.environ.get("SPICE_MODEL_DIR")) -except: - os.environ["SPICE_MODEL_DIR"] = "/mada/software/techfiles/scn3me_subm" +# try: +# SPICE_MODEL_DIR = os.path.abspath(os.environ.get("SPICE_MODEL_DIR")) +# except: +os.environ["SPICE_MODEL_DIR"] = "{0}/{1}/models".format(OPENRAM_TECH, TECHNOLOGY) ########################## # Paths required for OPENRAM to function