From e17c69be3e145d6a69392cfd55ccc3018faf3058 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Tue, 28 Aug 2018 10:24:09 -0700 Subject: [PATCH] Clean up new code for add_modules, add_pins and netlist/layouts. --- compiler/base/geometry.py | 2 +- compiler/example_config_freepdk45.py | 2 +- compiler/example_config_scn3me_subm.py | 3 +- compiler/globals.py | 1 - compiler/modules/bank.py | 24 +- compiler/modules/bitcell_array.py | 45 +-- compiler/modules/delay_chain.py | 2 +- compiler/modules/dff_array.py | 33 +- compiler/modules/dff_buf.py | 64 ++-- compiler/modules/dff_buf_array.py | 4 +- compiler/modules/dff_inv.py | 2 - compiler/modules/dff_inv_array.py | 4 +- compiler/modules/ms_flop_array.py | 36 +- compiler/modules/precharge_array.py | 16 +- compiler/modules/replica_bitline.py | 29 +- compiler/modules/sense_amp_array.py | 64 ++-- .../modules/single_level_column_mux_array.py | 30 +- compiler/modules/tri_gate_array.py | 41 +-- compiler/modules/wordline_driver.py | 3 +- compiler/modules/write_driver_array.py | 40 ++- compiler/pgates/pbitcell.py | 318 +++++++++++------- compiler/pgates/single_level_column_mux.py | 34 +- compiler/tests/04_pbitcell_test.py | 2 +- 23 files changed, 466 insertions(+), 333 deletions(-) diff --git a/compiler/base/geometry.py b/compiler/base/geometry.py index 2f7931ad..2e9bc2bb 100644 --- a/compiler/base/geometry.py +++ b/compiler/base/geometry.py @@ -199,7 +199,7 @@ class instance(geometry): """ This updates the placement of an instance. """ debug.info(3, "placing instance {}".format(self.name)) # Update the placement of an already added instance - self.offset = offset + self.offset = vector(offset) self.mirror = mirror self.rotate = rotate self.update_boundary() diff --git a/compiler/example_config_freepdk45.py b/compiler/example_config_freepdk45.py index 2c4c087e..774d41fb 100644 --- a/compiler/example_config_freepdk45.py +++ b/compiler/example_config_freepdk45.py @@ -8,5 +8,5 @@ supply_voltages = [1.0] temperatures = [25] output_path = "temp" -output_name = "sram_2_16_1_freepdk45" +output_name = "sram_{0}_{1}_{2}_{3}".format(word_size,num_words,num_banks,tech_name) diff --git a/compiler/example_config_scn3me_subm.py b/compiler/example_config_scn3me_subm.py index 491fa4d2..356b4542 100644 --- a/compiler/example_config_scn3me_subm.py +++ b/compiler/example_config_scn3me_subm.py @@ -7,7 +7,6 @@ process_corners = ["TT"] supply_voltages = [ 5.0 ] temperatures = [ 25 ] - output_path = "temp" -output_name = "sram_2_16_1_scn3me_subm" +output_name = "sram_{0}_{1}_{2}_{3}".format(word_size,num_words,num_banks,tech_name) diff --git a/compiler/globals.py b/compiler/globals.py index 02168e37..ff07906f 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -207,7 +207,6 @@ def read_config(config_file, is_unit_test=True): # If we are only generating a netlist, we can't do DRC/LVS if OPTS.netlist_only: OPTS.check_lvsdrc=False - # If config didn't set output name, make a reasonable default. if (OPTS.output_name == ""): diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 5547b99d..9e711d22 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -22,17 +22,6 @@ class bank(design.design): def __init__(self, word_size, num_words, words_per_row, num_banks=1, name=""): - mod_list = ["bitcell", "decoder", "ms_flop_array", "wordline_driver", - "bitcell_array", "sense_amp_array", "precharge_array", - "column_mux_array", "write_driver_array", - "dff", "bank_select"] - from importlib import reload - for mod_name in mod_list: - config_mod_name = getattr(OPTS, mod_name) - class_file = reload(__import__(config_mod_name)) - mod_class = getattr(class_file , config_mod_name) - setattr (self, "mod_"+mod_name, mod_class) - if name == "": name = "bank_{0}_{1}".format(word_size, num_words) design.design.__init__(self, name) @@ -206,6 +195,19 @@ class bank(design.design): def add_modules(self): """ Create all the modules using the class loader """ + + mod_list = ["bitcell", "decoder", "ms_flop_array", "wordline_driver", + "bitcell_array", "sense_amp_array", "precharge_array", + "column_mux_array", "write_driver_array", + "dff", "bank_select"] + from importlib import reload + for mod_name in mod_list: + config_mod_name = getattr(OPTS, mod_name) + class_file = reload(__import__(config_mod_name)) + mod_class = getattr(class_file , config_mod_name) + setattr (self, "mod_"+mod_name, mod_class) + + self.bitcell = self.mod_bitcell() self.bitcell_array = self.mod_bitcell_array(cols=self.num_cols, diff --git a/compiler/modules/bitcell_array.py b/compiler/modules/bitcell_array.py index de5034c2..0eb1fbf3 100644 --- a/compiler/modules/bitcell_array.py +++ b/compiler/modules/bitcell_array.py @@ -21,16 +21,6 @@ class bitcell_array(design.design): self.column_size = cols self.row_size = rows - from importlib import reload - c = reload(__import__(OPTS.bitcell)) - self.mod_bitcell = getattr(c, OPTS.bitcell) - self.cell = self.mod_bitcell() - self.add_mod(self.cell) - - # We increase it by a well enclosure so the precharges don't overlap our wells - self.height = self.row_size*self.cell.height + drc["well_enclosure_active"] + self.m1_width - self.width = self.column_size*self.cell.width + self.m1_width - self.create_netlist() if not OPTS.netlist_only: self.create_layout() @@ -42,17 +32,16 @@ class bitcell_array(design.design): def create_netlist(self): """ Create and connect the netlist """ + self.add_modules() self.add_pins() - - self.cell_inst = {} - for col in range(self.column_size): - for row in range(self.row_size): - name = "bit_r{0}_c{1}".format(row, col) - self.cell_inst[row,col]=self.add_inst(name=name, - mod=self.cell) - self.connect_inst(self.cell.list_bitcell_pins(col, row)) + self.create_modules() def create_layout(self): + + # We increase it by a well enclosure so the precharges don't overlap our wells + self.height = self.row_size*self.cell.height + drc["well_enclosure_active"] + self.m1_width + self.width = self.column_size*self.cell.width + self.m1_width + xoffset = 0.0 for col in range(self.column_size): yoffset = 0.0 @@ -87,7 +76,25 @@ class bitcell_array(design.design): self.add_pin("vdd") self.add_pin("gnd") - + def add_modules(self): + """ Add the modules used in this design """ + + from importlib import reload + c = reload(__import__(OPTS.bitcell)) + self.mod_bitcell = getattr(c, OPTS.bitcell) + self.cell = self.mod_bitcell() + self.add_mod(self.cell) + + def create_modules(self): + """ Create the module instances used in this design """ + self.cell_inst = {} + for col in range(self.column_size): + for row in range(self.row_size): + name = "bit_r{0}_c{1}".format(row, col) + self.cell_inst[row,col]=self.add_inst(name=name, + mod=self.cell) + self.connect_inst(self.cell.list_bitcell_pins(col, row)) + def add_layout_pins(self): """ Add the layout pins """ diff --git a/compiler/modules/delay_chain.py b/compiler/modules/delay_chain.py index eb61df52..b8a57f15 100644 --- a/compiler/modules/delay_chain.py +++ b/compiler/modules/delay_chain.py @@ -30,8 +30,8 @@ class delay_chain(design.design): def create_netlist(self): - self.add_pins() self.add_modules() + self.add_pins() self.create_inverters() def create_layout(self): diff --git a/compiler/modules/dff_array.py b/compiler/modules/dff_array.py index 7c6ae90e..b1b1b361 100644 --- a/compiler/modules/dff_array.py +++ b/compiler/modules/dff_array.py @@ -20,27 +20,30 @@ class dff_array(design.design): design.design.__init__(self, name) debug.info(1, "Creating {0} rows={1} cols={2}".format(self.name, self.rows, self.columns)) + self.create_netlist() + if not OPTS.netlist_only: + self.create_layout() + + def create_netlist(self): + self.add_modules() + self.add_pins() + self.create_dff_array() + + def create_layout(self): + self.width = self.columns * self.dff.width + self.height = self.rows * self.dff.height + + self.place_dff_array() + self.add_layout_pins() + self.DRC_LVS() + + def add_modules(self): from importlib import reload c = reload(__import__(OPTS.dff)) self.mod_dff = getattr(c, OPTS.dff) self.dff = self.mod_dff("dff") self.add_mod(self.dff) - - self.width = self.columns * self.dff.width - self.height = self.rows * self.dff.height - - self.create_netlist() - self.create_layout() - - def create_netlist(self): - self.add_pins() - self.create_dff_array() - def create_layout(self): - self.place_dff_array() - self.add_layout_pins() - self.DRC_LVS() - def add_pins(self): for row in range(self.rows): for col in range(self.columns): diff --git a/compiler/modules/dff_buf.py b/compiler/modules/dff_buf.py index 34d9b7f3..395216bf 100644 --- a/compiler/modules/dff_buf.py +++ b/compiler/modules/dff_buf.py @@ -26,29 +26,41 @@ class dff_buf(design.design): debug.check(inv1_size>=2, "Inverter must be greater than two for rail spacing DRC rules.") debug.check(inv2_size>=2, "Inverter must be greater than two for rail spacing DRC rules.") + self.inv1_size=inv1_size + self.inv2_size=inv2_size + + self.create_netlist() + if not OPTS.netlist_only: + self.create_layout() + + def create_netlist(self): + self.add_modules() + self.add_pins() + self.create_modules() + + def create_layout(self): + self.width = self.dff.width + self.inv1.width + self.inv2.width + self.height = self.dff.height + + self.place_modules() + self.route_wires() + self.add_layout_pins() + self.DRC_LVS() + + def add_modules(self): from importlib import reload c = reload(__import__(OPTS.dff)) self.mod_dff = getattr(c, OPTS.dff) self.dff = self.mod_dff("dff") self.add_mod(self.dff) - self.inv1 = pinv(size=inv1_size,height=self.dff.height) + self.inv1 = pinv(size=self.inv1_size,height=self.dff.height) self.add_mod(self.inv1) - self.inv2 = pinv(size=inv2_size,height=self.dff.height) + self.inv2 = pinv(size=self.inv2_size,height=self.dff.height) self.add_mod(self.inv2) - self.width = self.dff.width + self.inv1.width + self.inv2.width - self.height = self.dff.height - - self.create_layout() - - def create_layout(self): - self.add_pins() - self.add_insts() - self.add_wires() - self.add_layout_pins() - self.DRC_LVS() + def add_pins(self): self.add_pin("D") @@ -58,26 +70,30 @@ class dff_buf(design.design): self.add_pin("vdd") self.add_pin("gnd") - def add_insts(self): - # Add the DFF + def create_modules(self): self.dff_inst=self.add_inst(name="dff_buf_dff", - mod=self.dff, - offset=vector(0,0)) + mod=self.dff) self.connect_inst(["D", "qint", "clk", "vdd", "gnd"]) - # Add INV1 to the right self.inv1_inst=self.add_inst(name="dff_buf_inv1", - mod=self.inv1, - offset=vector(self.dff_inst.rx(),0)) + mod=self.inv1) self.connect_inst(["qint", "Qb", "vdd", "gnd"]) - # Add INV2 to the right self.inv2_inst=self.add_inst(name="dff_buf_inv2", - mod=self.inv2, - offset=vector(self.inv1_inst.rx(),0)) + mod=self.inv2) self.connect_inst(["Qb", "Q", "vdd", "gnd"]) + + def place_modules(self): + # Add the DFF + self.dff_inst.place(vector(0,0)) + + # Add INV1 to the right + self.inv1_inst.place(vector(self.dff_inst.rx(),0)) - def add_wires(self): + # Add INV2 to the right + self.inv2_inst.place(vector(self.inv1_inst.rx(),0)) + + def route_wires(self): # Route dff q to inv1 a q_pin = self.dff_inst.get_pin("Q") a1_pin = self.inv1_inst.get_pin("A") diff --git a/compiler/modules/dff_buf_array.py b/compiler/modules/dff_buf_array.py index e221e724..cedf0404 100644 --- a/compiler/modules/dff_buf_array.py +++ b/compiler/modules/dff_buf_array.py @@ -29,7 +29,7 @@ class dff_buf_array(design.design): def create_netlist(self): self.add_pins() - self.add_dff() + self.add_modules() self.create_dff_array() def create_layout(self): @@ -51,7 +51,7 @@ class dff_buf_array(design.design): self.add_pin("vdd") self.add_pin("gnd") - def add_dff(self): + def add_modules(self): self.dff = dff_buf.dff_buf(self.inv1_size, self.inv2_size) self.add_mod(self.dff) diff --git a/compiler/modules/dff_inv.py b/compiler/modules/dff_inv.py index 8d51aa29..3a06c9c9 100644 --- a/compiler/modules/dff_inv.py +++ b/compiler/modules/dff_inv.py @@ -63,12 +63,10 @@ class dff_inv(design.design): self.add_mod(self.inv1) def create_modules(self): - # Add the DFF self.dff_inst=self.add_inst(name="dff_inv_dff", mod=self.dff) self.connect_inst(["D", "Q", "clk", "vdd", "gnd"]) - # Add INV1 to the right self.inv1_inst=self.add_inst(name="dff_inv_inv1", mod=self.inv1) self.connect_inst(["Q", "Qb", "vdd", "gnd"]) diff --git a/compiler/modules/dff_inv_array.py b/compiler/modules/dff_inv_array.py index 01ca3a47..c88fabd3 100644 --- a/compiler/modules/dff_inv_array.py +++ b/compiler/modules/dff_inv_array.py @@ -28,7 +28,7 @@ class dff_inv_array(design.design): def create_netlist(self): self.add_pins() - self.add_dff() + self.add_modules() self.create_dff_array() def create_layout(self): @@ -39,7 +39,7 @@ class dff_inv_array(design.design): self.add_layout_pins() self.DRC_LVS() - def add_dff(self): + def add_modules(self): self.dff = dff_inv.dff_inv(self.inv_size) self.add_mod(self.dff) diff --git a/compiler/modules/ms_flop_array.py b/compiler/modules/ms_flop_array.py index 4f266683..061ad9be 100644 --- a/compiler/modules/ms_flop_array.py +++ b/compiler/modules/ms_flop_array.py @@ -20,27 +20,31 @@ class ms_flop_array(design.design): design.design.__init__(self, name) debug.info(1, "Creating {}".format(self.name)) + self.words_per_row = int(self.columns / self.word_size) + + self.create_netlist() + if not OPTS.netlist_only: + self.create_layout() + + def create_netlist(self): + self.add_modules() + self.add_pins() + self.create_ms_flop_array() + + def create_layout(self): + self.width = self.columns * self.ms.width + self.height = self.ms.height + + self.place_ms_flop_array() + self.add_layout_pins() + self.DRC_LVS() + + def add_modules(self): from importlib import reload c = reload(__import__(OPTS.ms_flop)) self.mod_ms_flop = getattr(c, OPTS.ms_flop) self.ms = self.mod_ms_flop("ms_flop") self.add_mod(self.ms) - - self.width = self.columns * self.ms.width - self.height = self.ms.height - self.words_per_row = int(self.columns / self.word_size) - - self.create_netlist() - self.create_layout() - - def create_netlist(self): - self.add_pins() - self.create_ms_flop_array() - - def create_layout(self): - self.place_ms_flop_array() - self.add_layout_pins() - self.DRC_LVS() def add_pins(self): for i in range(self.word_size): diff --git a/compiler/modules/precharge_array.py b/compiler/modules/precharge_array.py index 9e2bce40..880288c6 100644 --- a/compiler/modules/precharge_array.py +++ b/compiler/modules/precharge_array.py @@ -20,9 +20,9 @@ class precharge_array(design.design): debug.info(1, "Creating {0}".format(self.name)) self.columns = columns - - self.pc_cell = precharge(name="precharge", size=size, bitcell_bl=bitcell_bl, bitcell_br=bitcell_br) - self.add_mod(self.pc_cell) + self.size = size + self.bitcell_bl = bitcell_bl + self.bitcell_br = bitcell_br self.create_netlist() if not OPTS.netlist_only: @@ -37,6 +37,7 @@ class precharge_array(design.design): self.add_pin("vdd") def create_netlist(self): + self.add_modules() self.add_pins() self.create_insts() @@ -47,8 +48,15 @@ class precharge_array(design.design): self.place_insts() self.add_layout_pins() self.DRC_LVS() - + def add_modules(self): + self.pc_cell = precharge(name="precharge", + size=self.size, + bitcell_bl=self.bitcell_bl, + bitcell_br=self.bitcell_br) + self.add_mod(self.pc_cell) + + def add_layout_pins(self): self.add_layout_pin(text="en", diff --git a/compiler/modules/replica_bitline.py b/compiler/modules/replica_bitline.py index 06f26417..ee3e89d4 100644 --- a/compiler/modules/replica_bitline.py +++ b/compiler/modules/replica_bitline.py @@ -18,13 +18,6 @@ class replica_bitline(design.design): def __init__(self, delay_stages, delay_fanout, bitcell_loads, name="replica_bitline"): design.design.__init__(self, name) - from importlib import reload - g = reload(__import__(OPTS.delay_chain)) - self.mod_delay_chain = getattr(g, OPTS.delay_chain) - - g = reload(__import__(OPTS.replica_bitcell)) - self.mod_replica_bitcell = getattr(g, OPTS.replica_bitcell) - self.bitcell_loads = bitcell_loads self.delay_stages = delay_stages self.delay_fanout = delay_fanout @@ -34,19 +27,17 @@ class replica_bitline(design.design): self.create_layout() def create_netlist(self): - for pin in ["en", "out", "vdd", "gnd"]: - self.add_pin(pin) self.add_modules() + self.add_pins() self.create_modules() def create_layout(self): self.calculate_module_offsets() self.place_modules() self.route() + self.add_layout_pins() self.offset_all_coordinates() - - self.add_layout_pins() #self.add_lvs_correspondence_points() @@ -56,6 +47,9 @@ class replica_bitline(design.design): self.DRC_LVS() + def add_pins(self): + for pin in ["en", "out", "vdd", "gnd"]: + self.add_pin(pin) def calculate_module_offsets(self): """ Calculate all the module offsets """ @@ -85,6 +79,14 @@ class replica_bitline(design.design): def add_modules(self): """ Add the modules for later usage """ + + from importlib import reload + g = reload(__import__(OPTS.delay_chain)) + self.mod_delay_chain = getattr(g, OPTS.delay_chain) + + g = reload(__import__(OPTS.replica_bitcell)) + self.mod_replica_bitcell = getattr(g, OPTS.replica_bitcell) + self.bitcell = self.replica_bitcell = self.mod_replica_bitcell() self.add_mod(self.bitcell) @@ -267,8 +269,6 @@ class replica_bitline(design.design): self.copy_layout_pin(self.dc_inst,"vdd") self.copy_layout_pin(self.rbc_inst,"vdd") - - # Connect the WL and vdd pins directly to the center and right vdd rails # Connect RBL vdd pins to center and right rails rbl_vdd_pins = self.rbl_inst.get_pins("vdd") @@ -288,9 +288,6 @@ class replica_bitline(design.design): offset=end, rotate=90) - - - # Add via for the inverter pin = self.rbl_inv_inst.get_pin("vdd") start = vector(self.left_vdd_pin.cx(),pin.cy()) diff --git a/compiler/modules/sense_amp_array.py b/compiler/modules/sense_amp_array.py index c2fc5c82..47bcf023 100644 --- a/compiler/modules/sense_amp_array.py +++ b/compiler/modules/sense_amp_array.py @@ -14,44 +14,46 @@ class sense_amp_array(design.design): design.design.__init__(self, "sense_amp_array") debug.info(1, "Creating {0}".format(self.name)) + self.word_size = word_size + self.words_per_row = words_per_row + self.row_size = self.word_size * self.words_per_row + + self.create_netlist() + if not OPTS.netlist_only: + self.create_layout() + + + def create_netlist(self): + self.add_modules() + self.add_pins() + self.create_sense_amp_array() + + def create_layout(self): + self.height = self.amp.height + self.width = self.amp.width * self.word_size * self.words_per_row + + self.place_sense_amp_array() + self.add_layout_pins() + self.route_rails() + self.DRC_LVS() + + def add_pins(self): + for i in range(0,self.word_size): + self.add_pin("data[{0}]".format(i)) + self.add_pin("bl[{0}]".format(i)) + self.add_pin("br[{0}]".format(i)) + self.add_pin("en") + self.add_pin("vdd") + self.add_pin("gnd") + + def add_modules(self): from importlib import reload c = reload(__import__(OPTS.sense_amp)) self.mod_sense_amp = getattr(c, OPTS.sense_amp) self.amp = self.mod_sense_amp("sense_amp") self.add_mod(self.amp) - self.word_size = word_size - self.words_per_row = words_per_row - self.row_size = self.word_size * self.words_per_row - - self.height = self.amp.height - self.width = self.amp.width * self.word_size * self.words_per_row - - self.create_netlist() - self.create_layout() - self.DRC_LVS() - - def add_pins(self): - - for i in range(0,self.word_size): - self.add_pin("data[{0}]".format(i)) - self.add_pin("bl[{0}]".format(i)) - self.add_pin("br[{0}]".format(i)) - - self.add_pin("en") - self.add_pin("vdd") - self.add_pin("gnd") - - def create_netlist(self): - self.add_pins() - self.create_sense_amp_array() - def create_layout(self): - self.place_sense_amp_array() - self.add_layout_pins() - self.route_rails() - - def create_sense_amp_array(self): self.local_insts = [] for i in range(0,self.word_size): diff --git a/compiler/modules/single_level_column_mux_array.py b/compiler/modules/single_level_column_mux_array.py index a732ce74..d9be378f 100644 --- a/compiler/modules/single_level_column_mux_array.py +++ b/compiler/modules/single_level_column_mux_array.py @@ -6,7 +6,7 @@ from tech import drc import debug import math from vector import vector - +from globals import OPTS class single_level_column_mux_array(design.design): """ @@ -20,23 +20,14 @@ class single_level_column_mux_array(design.design): self.columns = columns self.word_size = word_size self.words_per_row = int(self.columns / self.word_size) + self.create_netlist() - self.create_layout() - - def add_pins(self): - for i in range(self.columns): - self.add_pin("bl[{}]".format(i)) - self.add_pin("br[{}]".format(i)) - for i in range(self.words_per_row): - self.add_pin("sel[{}]".format(i)) - for i in range(self.word_size): - self.add_pin("bl_out[{}]".format(i)) - self.add_pin("br_out[{}]".format(i)) - self.add_pin("gnd") + if not OPTS.netlist_only: + self.create_layout() def create_netlist(self): - self.add_pins() self.add_modules() + self.add_pins() self.create_array() def create_layout(self): @@ -51,6 +42,17 @@ class single_level_column_mux_array(design.design): self.DRC_LVS() + def add_pins(self): + for i in range(self.columns): + self.add_pin("bl[{}]".format(i)) + self.add_pin("br[{}]".format(i)) + for i in range(self.words_per_row): + self.add_pin("sel[{}]".format(i)) + for i in range(self.word_size): + self.add_pin("bl_out[{}]".format(i)) + self.add_pin("br_out[{}]".format(i)) + self.add_pin("gnd") + def add_modules(self): # FIXME: Why is this 8x? diff --git a/compiler/modules/tri_gate_array.py b/compiler/modules/tri_gate_array.py index 5eff379a..f8b939af 100644 --- a/compiler/modules/tri_gate_array.py +++ b/compiler/modules/tri_gate_array.py @@ -14,31 +14,34 @@ class tri_gate_array(design.design): design.design.__init__(self, "tri_gate_array") debug.info(1, "Creating {0}".format(self.name)) + self.columns = columns + self.word_size = word_size + self.words_per_row = int(self.columns / self.word_size) + + self.create_netlist() + if not OPTS.netlist_only: + self.create_layout() + + def create_netlist(self): + self.add_modules() + self.add_pins() + self.create_array() + + def create_layout(self): + self.width = (self.columns / self.words_per_row) * self.tri.width + self.height = self.tri.height + + self.place_array() + self.add_layout_pins() + self.DRC_LVS() + + def add_modules(self): from importlib import reload c = reload(__import__(OPTS.tri_gate)) self.mod_tri_gate = getattr(c, OPTS.tri_gate) self.tri = self.mod_tri_gate("tri_gate") self.add_mod(self.tri) - - self.columns = columns - self.word_size = word_size - - self.words_per_row = int(self.columns / self.word_size) - self.width = (self.columns / self.words_per_row) * self.tri.width - self.height = self.tri.height - self.create_netlist() - self.create_layout() - - def create_netlist(self): - self.add_pins() - self.create_array() - - def create_layout(self): - self.place_array() - self.add_layout_pins() - self.DRC_LVS() - def add_pins(self): """create the name of pins depend on the word size""" for i in range(self.word_size): diff --git a/compiler/modules/wordline_driver.py b/compiler/modules/wordline_driver.py index 2d4ef224..709e3e45 100644 --- a/compiler/modules/wordline_driver.py +++ b/compiler/modules/wordline_driver.py @@ -20,13 +20,14 @@ class wordline_driver(design.design): design.design.__init__(self, "wordline_driver") self.rows = rows + self.create_netlist() if not OPTS.netlist_only: self.create_layout() def create_netlist(self): - self.add_pins() self.add_modules() + self.add_pins() self.create_drivers() def create_layout(self): diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index 4f6bd146..965f1735 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -15,21 +15,27 @@ class write_driver_array(design.design): design.design.__init__(self, "write_driver_array") debug.info(1, "Creating {0}".format(self.name)) - from importlib import reload - c = reload(__import__(OPTS.write_driver)) - self.mod_write_driver = getattr(c, OPTS.write_driver) - self.driver = self.mod_write_driver("write_driver") - self.add_mod(self.driver) - self.columns = columns self.word_size = word_size self.words_per_row = int(columns / word_size) - self.width = self.columns * self.driver.width - self.height = self.height = self.driver.height - self.create_netlist() - self.create_layout() + if not OPTS.netlist_only: + self.create_layout() + + + def create_netlist(self): + self.add_modules() + self.add_pins() + self.create_write_array() + + def create_layout(self): + self.width = self.columns * self.driver.width + self.height = self.driver.height + + self.place_write_array() + self.add_layout_pins() + self.DRC_LVS() def add_pins(self): for i in range(self.word_size): @@ -41,14 +47,12 @@ class write_driver_array(design.design): self.add_pin("vdd") self.add_pin("gnd") - def create_netlist(self): - self.add_pins() - self.create_write_array() - - def create_layout(self): - self.place_write_array() - self.add_layout_pins() - self.DRC_LVS() + def add_modules(self): + from importlib import reload + c = reload(__import__(OPTS.write_driver)) + self.mod_write_driver = getattr(c, OPTS.write_driver) + self.driver = self.mod_write_driver("write_driver") + self.add_mod(self.driver) def create_write_array(self): self.driver_insts = {} diff --git a/compiler/pgates/pbitcell.py b/compiler/pgates/pbitcell.py index c2dccc42..ac6ace3b 100644 --- a/compiler/pgates/pbitcell.py +++ b/compiler/pgates/pbitcell.py @@ -37,10 +37,39 @@ class pbitcell(pgate.pgate): pbitcell.height = self.height + + def create_netlist(self): + self.add_pins() + self.add_modules() + self.create_storage() + + if(self.num_readwrite > 0): + self.create_readwrite_ports() + if(self.num_write > 0): + self.create_write_ports() + if(self.num_read > 0): + self.create_read_ports() + + def create_layout(self): + self.calculate_spacing() + self.calculate_postions() + + self.place_storage() + self.route_storage() + self.route_rails() + + if(self.num_readwrite > 0): + self.place_readwrite_ports() + if(self.num_write > 0): + self.place_write_ports() + if(self.num_read > 0): + self.place_read_ports() + self.extend_well() + + self.offset_all_coordinates() + self.DRC_LVS() + def add_pins(self): - """ - Adding pins for pbitcell module - """ for k in range(self.num_readwrite): self.add_pin("rwbl{}".format(k)) self.add_pin("rwbl_bar{}".format(k)) @@ -61,33 +90,8 @@ class pbitcell(pgate.pgate): self.add_pin("vdd") self.add_pin("gnd") - - def create_netlist(self): - self.add_pins() - - def create_layout(self): - self.create_ptx() - self.calculate_spacing() - self.calculate_postions() - self.add_storage() - self.add_rails() - if(self.num_readwrite > 0): - self.add_readwrite_ports() - if(self.num_write > 0): - self.add_write_ports() - if(self.num_read > 0): - self.add_read_ports() - self.extend_well() - self.offset_all_coordinates() - self.DRC_LVS() - - def create_ptx(self): - """ - Calculate transistor sizes and create ptx for read/write, write, and read ports - """ - - """ calculate transistor sizes """ + def add_modules(self): # if there are any read/write ports, then the inverter nmos is sized based the number of them if(self.num_readwrite > 0): inverter_nmos_width = self.num_readwrite*3*parameter["min_tx_size"] @@ -131,11 +135,9 @@ class pbitcell(pgate.pgate): def calculate_spacing(self): - """ - Calculate transistor spacings - """ + """ Calculate transistor spacings """ - """ calculate metal contact extensions over transistor active """ + # calculate metal contact extensions over transistor active self.inverter_pmos_contact_extension = 0.5*(self.inverter_pmos.active_contact.height - self.inverter_pmos.active_height) self.readwrite_nmos_contact_extension = 0.5*(self.readwrite_nmos.active_contact.height - self.readwrite_nmos.active_height) self.write_nmos_contact_extension = 0.5*(self.write_nmos.active_contact.height - self.write_nmos.active_height) @@ -144,7 +146,7 @@ class pbitcell(pgate.pgate): # calculate the distance threshold for different gate contact spacings self.gate_contact_thres = drc["poly_to_active"] - drc["minwidth_metal2"] - """ calculations for horizontal transistor to tansistor spacing """ + #calculations for horizontal transistor to tansistor spacing # inverter spacings self.inverter_to_inverter_spacing = contact.poly.height + drc["minwidth_metal1"] self.inverter_to_write_spacing = drc["pwell_to_nwell"] + 2*drc["well_enclosure_active"] @@ -266,9 +268,9 @@ class pbitcell(pgate.pgate): self.height = self.topmost_ypos - self.botmost_ypos - array_vdd_overlap - def add_storage(self): + def place_storage(self): """ - Creates the crossed coupled inverters that act as storage for the bitcell. + Places the crossed coupled inverters that act as storage for the bitcell. The stored value of the cell is denoted as "Q", and the inverted value as "Q_bar". """ @@ -278,26 +280,14 @@ class pbitcell(pgate.pgate): inverter_pmos_ypos = self.inverter_nmos.active_height + self.inverter_gap # create active for nmos - self.inverter_nmos_left = self.add_inst(name="inverter_nmos_left", - mod=self.inverter_nmos, - offset=[left_inverter_xpos,0]) - self.connect_inst(["Q_bar", "Q", "gnd", "gnd"]) - - self.inverter_nmos_right = self.add_inst(name="inverter_nmos_right", - mod=self.inverter_nmos, - offset=[right_inverter_xpos,0]) - self.connect_inst(["gnd", "Q_bar", "Q", "gnd"]) + self.inverter_nmos_left.place([left_inverter_xpos,0]) + self.inverter_nmos_right.place([right_inverter_xpos,0]) # create active for pmos - self.inverter_pmos_left = self.add_inst(name="inverter_pmos_left", - mod=self.inverter_pmos, - offset=[left_inverter_xpos, inverter_pmos_ypos]) - self.connect_inst(["Q_bar", "Q", "vdd", "vdd"]) - - self.inverter_pmos_right = self.add_inst(name="inverter_pmos_right", - mod=self.inverter_pmos, - offset=[right_inverter_xpos, inverter_pmos_ypos]) - self.connect_inst(["vdd", "Q_bar", "Q", "vdd"]) + self.inverter_pmos_left.place([left_inverter_xpos, inverter_pmos_ypos]) + self.inverter_pmos_right.place([right_inverter_xpos, inverter_pmos_ypos]) + + def route_storage(self): # connect input (gate) of inverters self.add_path("poly", [self.inverter_nmos_left.get_pin("G").uc(), self.inverter_pmos_left.get_pin("G").bc()]) @@ -329,13 +319,38 @@ class pbitcell(pgate.pgate): self.left_building_edge = -self.inverter_tile_width self.right_building_edge = self.inverter_tile_width - - def add_rails(self): + + def create_storage(self): + """ + Creates the crossed coupled inverters that act as storage for the bitcell. + The stored value of the cell is denoted as "Q", and the inverted value as "Q_bar". + """ + + # create active for nmos + self.inverter_nmos_left = self.add_inst(name="inverter_nmos_left", + mod=self.inverter_nmos) + self.connect_inst(["Q_bar", "Q", "gnd", "gnd"]) + + self.inverter_nmos_right = self.add_inst(name="inverter_nmos_right", + mod=self.inverter_nmos) + self.connect_inst(["gnd", "Q_bar", "Q", "gnd"]) + + # create active for pmos + self.inverter_pmos_left = self.add_inst(name="inverter_pmos_left", + mod=self.inverter_pmos) + self.connect_inst(["Q_bar", "Q", "vdd", "vdd"]) + + self.inverter_pmos_right = self.add_inst(name="inverter_pmos_right", + mod=self.inverter_pmos) + self.connect_inst(["vdd", "Q_bar", "Q", "vdd"]) + + + def route_rails(self): """ Add gnd and vdd rails and connects them to the inverters """ - """ Add rails for vdd and gnd """ + # Add rails for vdd and gnd self.gnd_position = vector(self.leftmost_xpos, -self.rail_tile_height) self.gnd = self.add_layout_pin(text="gnd", layer="metal1", @@ -352,7 +367,7 @@ class pbitcell(pgate.pgate): width=self.width, height=drc["minwidth_metal1"]) - """ Connect inverters to rails """ + # Connect inverters to rails # connect inverter nmos to gnd gnd_pos_left = vector(self.inverter_nmos_left.get_pin("S").bc().x, self.gnd_position.y) self.add_path("metal1", [self.inverter_nmos_left.get_pin("S").bc(), gnd_pos_left]) @@ -368,9 +383,9 @@ class pbitcell(pgate.pgate): self.add_path("metal1", [self.inverter_pmos_right.get_pin("D").uc(), vdd_pos_right]) - def add_readwrite_ports(self): + def create_readwrite_ports(self): """ - Adds read/write ports to the bit cell. A differential pair of transistor can both read and write, like in a 6T cell. + Creates read/write ports to the bit cell. A differential pair of transistor can both read and write, like in a 6T cell. A read or write is enabled by setting a Read-Write-Wordline (RWWL) high, subsequently turning on the transistor. The transistor is connected between a Read-Write-Bitline (RWBL) and the storage component of the cell (Q). In a write operation, driving RWBL high or low sets the value of the cell. @@ -378,20 +393,38 @@ class pbitcell(pgate.pgate): This is a differential design, so each write port has a mirrored port that connects RWBL_bar to Q_bar. """ - """ Define variables relevant to write transistors """ - # define offset correction due to rotation of the ptx module - readwrite_rotation_correct = self.readwrite_nmos.active_height - # define write transistor variables as empty arrays based on the number of write ports self.readwrite_nmos_left = [None] * self.num_readwrite self.readwrite_nmos_right = [None] * self.num_readwrite + + # iterate over the number of read/write ports + for k in range(0,self.num_readwrite): + # add read/write transistors + self.readwrite_nmos_left[k] = self.add_inst(name="readwrite_nmos_left{}".format(k), + mod=self.readwrite_nmos) + self.connect_inst(["Q", "rwwl{}".format(k), "rwbl{}".format(k), "gnd"]) + + self.readwrite_nmos_right[k] = self.add_inst(name="readwrite_nmos_right{}".format(k), + mod=self.readwrite_nmos) + self.connect_inst(["Q_bar", "rwwl{}".format(k), "rwbl_bar{}".format(k), "gnd"]) + + + def place_readwrite_ports(self): + """ + Places read/write ports in the bit cell. + """ + + # Define variables relevant to write transistors self.rwwl_positions = [None] * self.num_readwrite self.rwbl_positions = [None] * self.num_readwrite self.rwbl_bar_positions = [None] * self.num_readwrite + # define offset correction due to rotation of the ptx module + readwrite_rotation_correct = self.readwrite_nmos.active_height + # iterate over the number of read/write ports for k in range(0,self.num_readwrite): - """ Add transistors """ + # Add transistors # calculate read/write transistor offsets left_readwrite_transistor_xpos = self.left_building_edge \ - self.inverter_to_write_spacing \ @@ -404,19 +437,13 @@ class pbitcell(pgate.pgate): + readwrite_rotation_correct # add read/write transistors - self.readwrite_nmos_left[k] = self.add_inst(name="readwrite_nmos_left{}".format(k), - mod=self.readwrite_nmos, - offset=[left_readwrite_transistor_xpos,0], - rotate=90) - self.connect_inst(["Q", "rwwl{}".format(k), "rwbl{}".format(k), "gnd"]) + self.readwrite_nmos_left[k].place(offset=[left_readwrite_transistor_xpos,0], + rotate=90) - self.readwrite_nmos_right[k] = self.add_inst(name="readwrite_nmos_right{}".format(k), - mod=self.readwrite_nmos, - offset=[right_readwrite_transistor_xpos,0], - rotate=90) - self.connect_inst(["Q_bar", "rwwl{}".format(k), "rwbl_bar{}".format(k), "gnd"]) + self.readwrite_nmos_right[k].place(offset=[right_readwrite_transistor_xpos,0], + rotate=90) - """ Add RWWL lines """ + # Add RWWL lines # calculate RWWL position rwwl_ypos = self.gnd_position.y - (k+1)*self.rowline_tile_height self.rwwl_positions[k] = vector(self.leftmost_xpos, rwwl_ypos) @@ -428,7 +455,7 @@ class pbitcell(pgate.pgate): width=self.width, height=contact.m1m2.width) - """ Source/RWBL/RWBL_bar connections """ + # Source/RWBL/RWBL_bar connections # add metal1-to-metal2 contacts on top of read/write transistor source pins for connection to WBL and WBL_bar offset_left = self.readwrite_nmos_left[k].get_pin("S").center() self.add_contact_center(layers=("metal1", "via1", "metal2"), @@ -455,7 +482,7 @@ class pbitcell(pgate.pgate): width=drc["minwidth_metal2"], height=self.height) - """ Gate/RWWL connections """ + # Gate/RWWL connections # add poly-to-meltal2 contacts to connect gate of read/write transistors to RWWL (contact next to gate) # contact must be placed a metal1 width below the source pin to avoid drc from source pin routings if(self.readwrite_nmos_contact_extension > self.gate_contact_thres): @@ -504,7 +531,7 @@ class pbitcell(pgate.pgate): self.add_path("metal2", [left_gate_contact, left_rwwl_contact]) self.add_path("metal2", [right_gate_contact, right_rwwl_contact]) - """ Drain/Storage connections """ + # Drain/Storage connections # this path only needs to be drawn once on the last iteration of the loop if(k == self.num_readwrite-1): # add contacts to connect gate of inverters to drain of read/write transistors @@ -538,34 +565,56 @@ class pbitcell(pgate.pgate): # end if # end for - """ update furthest left and right transistor edges """ + # update furthest left and right transistor edges self.left_building_edge = left_readwrite_transistor_xpos - self.readwrite_nmos.active_height self.right_building_edge = right_readwrite_transistor_xpos + - - def add_write_ports(self): + def create_write_ports(self): """ - Adds write ports to the bit cell. A differential pair of transistors can write only. + Creates write ports in the bit cell. A differential pair of transistors can write only. A write is enabled by setting a Write-Rowline (WWL) high, subsequently turning on the transistor. The transistor is connected between a Write-Bitline (WBL) and the storage component of the cell (Q). In a write operation, driving WBL high or low sets the value of the cell. This is a differential design, so each write port has a mirrored port that connects WBL_bar to Q_bar. """ - """ Define variables relevant to write transistors """ + # Define variables relevant to write transistors # define offset correction due to rotation of the ptx module write_rotation_correct = self.write_nmos.active_height # define write transistor variables as empty arrays based on the number of write ports self.write_nmos_left = [None] * self.num_write self.write_nmos_right = [None] * self.num_write - self.wwl_positions = [None] * self.num_write - self.wbl_positions = [None] * self.num_write - self.wbl_bar_positions = [None] * self.num_write # iterate over the number of write ports for k in range(0,self.num_write): - """ Add transistors """ + # add write transistors + self.write_nmos_left[k] = self.add_inst(name="write_nmos_left{}".format(k), + mod=self.write_nmos) + self.connect_inst(["Q", "wwl{}".format(k), "wbl{}".format(k), "gnd"]) + + self.write_nmos_right[k] = self.add_inst(name="write_nmos_right{}".format(k), + mod=self.write_nmos) + self.connect_inst(["Q_bar", "wwl{}".format(k), "wbl_bar{}".format(k), "gnd"]) + + + def place_write_ports(self): + """ + Places write ports in the bit cell. + """ + + # Define variables relevant to write transistors + self.wwl_positions = [None] * self.num_write + self.wbl_positions = [None] * self.num_write + self.wbl_bar_positions = [None] * self.num_write + + # define offset correction due to rotation of the ptx module + write_rotation_correct = self.write_nmos.active_height + + # iterate over the number of write ports + for k in range(0,self.num_write): + # Add transistors # calculate write transistor offsets left_write_transistor_xpos = self.left_building_edge \ - (not self.readwrite_port_flag)*self.inverter_to_write_spacing \ @@ -580,19 +629,13 @@ class pbitcell(pgate.pgate): + write_rotation_correct # add write transistors - self.write_nmos_left[k] = self.add_inst(name="write_nmos_left{}".format(k), - mod=self.write_nmos, - offset=[left_write_transistor_xpos,0], - rotate=90) - self.connect_inst(["Q", "wwl{}".format(k), "wbl{}".format(k), "gnd"]) + self.write_nmos_left[k].place(offset=[left_write_transistor_xpos,0], + rotate=90) - self.write_nmos_right[k] = self.add_inst(name="write_nmos_right{}".format(k), - mod=self.write_nmos, - offset=[right_write_transistor_xpos,0], - rotate=90) - self.connect_inst(["Q_bar", "wwl{}".format(k), "wbl_bar{}".format(k), "gnd"]) + self.write_nmos_right[k].place(offset=[right_write_transistor_xpos,0], + rotate=90) - """ Add WWL lines """ + # Add WWL lines # calculate WWL position wwl_ypos = self.gnd_position.y \ - self.num_readwrite*self.rowline_tile_height \ @@ -606,7 +649,7 @@ class pbitcell(pgate.pgate): width=self.width, height=contact.m1m2.width) - """ Source/WBL/WBL_bar connections """ + # Source/WBL/WBL_bar connections # add metal1-to-metal2 contacts on top of write transistor source pins for connection to WBL and WBL_bar offset_left = self.write_nmos_left[k].get_pin("S").center() self.add_contact_center(layers=("metal1", "via1", "metal2"), @@ -633,7 +676,7 @@ class pbitcell(pgate.pgate): width=drc["minwidth_metal2"], height=self.height) - """ Gate/WWL connections """ + # Gate/WWL connections # add poly-to-meltal2 contacts to connect gate of write transistors to WWL (contact next to gate) # contact must be placed a metal width below the source pin to avoid drc from source pin routings if(self.write_nmos_contact_extension > self.gate_contact_thres): @@ -682,7 +725,7 @@ class pbitcell(pgate.pgate): self.add_path("metal2", [left_gate_contact, left_wwl_contact]) self.add_path("metal2", [right_gate_contact, right_wwl_contact]) - """ Drain/Storage connections """ + # Drain/Storage connections # this path only needs to be drawn once on the last iteration of the loop if(k == self.num_write-1): # add contacts to connect gate of inverters to drain of write transistors @@ -713,17 +756,15 @@ class pbitcell(pgate.pgate): midR1 = vector(self.inverter_nmos_right.get_pin("D").rc().x + 1.5*drc["minwidth_metal1"], self.write_nmos_right[k].get_pin("D").rc().y) self.add_path("metal1", [right_storage_contact, midR0], width=contact.poly.second_layer_width) self.add_path("metal1", [midR0+vector(0,0.5*contact.poly.second_layer_width), midR1, self.write_nmos_right[k].get_pin("D").rc()]) - # end if - # end for - """ update furthest left and right transistor edges """ + # update furthest left and right transistor edges self.left_building_edge = left_write_transistor_xpos - self.write_nmos.active_height self.right_building_edge = right_write_transistor_xpos - def add_read_ports(self): + def create_read_ports(self): """ - Adds read ports to the bit cell. A differential pair of ports can read only. + Creates read ports in the bit cell. A differential pair of ports can read only. Two transistors function as a read port, denoted as the "read transistor" and the "read-access transistor". The read transistor is connected to RWL (gate), RBL (drain), and the read-access transistor (source). The read-access transistor is connected to Q_bar (gate), gnd (source), and the read transistor (drain). @@ -733,7 +774,42 @@ class pbitcell(pgate.pgate): using sense amps. This is a differential design, so each read port has a mirrored port that connects RBL_bar to Q. """ - """ Define variables relevant to read transistors """ + # define read transistor variables as empty arrays based on the number of read ports + self.read_nmos_left = [None] * self.num_read + self.read_nmos_right = [None] * self.num_read + self.read_access_nmos_left = [None] * self.num_read + self.read_access_nmos_right = [None] * self.num_read + + # iterate over the number of read ports + for k in range(0,self.num_read): + # add read-access transistors + self.read_access_nmos_left[k] = self.add_inst(name="read_access_nmos_left{}".format(k), + mod=self.read_nmos) + self.connect_inst(["RA_to_R_left{}".format(k), " Q_bar", "gnd", "gnd"]) + + self.read_access_nmos_right[k] = self.add_inst(name="read_access_nmos_right{}".format(k), + mod=self.read_nmos) + self.connect_inst(["RA_to_R_right{}".format(k), "Q", "gnd", "gnd"]) + + # add read transistors + self.read_nmos_left[k] = self.add_inst(name="read_nmos_left{}".format(k), + mod=self.read_nmos) + self.connect_inst(["rbl{}".format(k), "rwl{}".format(k), "RA_to_R_left{}".format(k), "gnd"]) + + self.read_nmos_right[k] = self.add_inst(name="read_nmos_right{}".format(k), + mod=self.read_nmos) + self.connect_inst(["rbl_bar{}".format(k), "rwl{}".format(k), "RA_to_R_right{}".format(k), "gnd"]) + + def place_read_ports(self): + """ + Places the read ports in the bit cell. + """ + + # Define variables relevant to read transistors + self.rwl_positions = [None] * self.num_read + self.rbl_positions = [None] * self.num_read + self.rbl_bar_positions = [None] * self.num_read + # define offset correction due to rotation of the ptx module read_rotation_correct = self.read_nmos.active_height @@ -751,7 +827,7 @@ class pbitcell(pgate.pgate): # iterate over the number of read ports for k in range(0,self.num_read): - """ Add transistors """ + # Add transistors # calculate transistor offsets left_read_transistor_xpos = self.left_building_edge \ - self.write_to_read_spacing \ @@ -789,7 +865,7 @@ class pbitcell(pgate.pgate): rotate=90) self.connect_inst(["rbl_bar{}".format(k), "rwl{}".format(k), "RA_to_R_right{}".format(k), "gnd"]) - """ Add RWL lines """ + # Add RWL lines # calculate RWL position rwl_ypos = self.gnd_position.y \ - self.num_readwrite*self.rowline_tile_height \ @@ -804,7 +880,7 @@ class pbitcell(pgate.pgate): width=self.width, height=contact.m1m2.width) - """ Drain of read transistor / RBL & RBL_bar connection """ + # Drain of read transistor / RBL & RBL_bar connection # add metal1-to-metal2 contacts on top of read transistor drain pins for connection to RBL and RBL_bar offset_left = self.read_nmos_left[k].get_pin("D").center() self.add_contact_center(layers=("metal1", "via1", "metal2"), @@ -831,7 +907,7 @@ class pbitcell(pgate.pgate): width=drc["minwidth_metal2"], height=self.height) - """ Gate of read transistor / RWL connection """ + # Gate of read transistor / RWL connection # add poly-to-meltal2 contacts to connect gate of read transistors to RWL (contact next to gate) if(self.read_nmos_contact_extension > self.gate_contact_thres): contact_xpos = self.read_nmos_left[k].get_pin("S").lc().x - drc["minwidth_metal2"] - 0.5*contact.m1m2.width @@ -876,7 +952,7 @@ class pbitcell(pgate.pgate): self.add_path("metal2", [left_gate_contact, left_rwl_contact]) self.add_path("metal2", [right_gate_contact, right_rwl_contact]) - """ Source of read-access transistor / GND connection """ + # Source of read-access transistor / GND connection # connect source of read-access transistor to GND (metal1 path) gnd_offset_left = vector(self.read_access_nmos_left[k].get_pin("S").bc().x, self.gnd_position.y) self.add_path("metal1", [self.read_access_nmos_left[k].get_pin("S").bc(), gnd_offset_left]) @@ -884,7 +960,7 @@ class pbitcell(pgate.pgate): gnd_offset_right = vector(self.read_access_nmos_right[k].get_pin("S").bc().x, self.gnd_position.y) self.add_path("metal1", [self.read_access_nmos_right[k].get_pin("S").bc(), gnd_offset_right]) - """ Gate of read-access transistor / storage connection """ + # Gate of read-access transistor / storage connection # add poly-to-metal1 contacts to connect gate of read-access transistors to output of inverters (contact next to gate) if(self.read_nmos_contact_extension > self.gate_contact_thres): contact_xpos = self.read_nmos_left[k].get_pin("S").rc().x + drc["minwidth_metal2"] + 0.5*contact.m1m2.width @@ -933,7 +1009,7 @@ class pbitcell(pgate.pgate): self.add_path("metal1", [right_gate_contact, midR0, midR1, midR2, right_inverter_offset]) # end for - + def extend_well(self): """ Connects wells between ptx modules to avoid drc spacing issues. @@ -941,7 +1017,7 @@ class pbitcell(pgate.pgate): the well connections must be done piecewise to avoid pwell and nwell overlap. """ - """ extend pwell to encompass entire nmos region of the cell up to the height of the inverter nmos well """ + # extend pwell to encompass entire nmos region of the cell up to the height of the inverter nmos well offset = vector(self.leftmost_xpos, self.botmost_ypos) well_height = -self.botmost_ypos + self.inverter_nmos.cell_well_height - drc["well_enclosure_active"] self.add_rect(layer="pwell", @@ -949,7 +1025,9 @@ class pbitcell(pgate.pgate): width=self.width, height=well_height) - """ extend pwell over read/write and write transistors to the height of the write transistor well (read/write and write transistors are the same height) """ + # extend pwell over read/write and write transistors to the + # height of the write transistor well (read/write and write + # transistors are the same height) if(self.num_write > 0): # calculate the edge of the write transistor well closest to the center left_write_well_xpos = self.write_nmos_left[0].offset.x + drc["well_enclosure_active"] @@ -975,7 +1053,7 @@ class pbitcell(pgate.pgate): width=write_well_width, height=write_well_height) - """ extend pwell over the read transistors to the height of the bitcell """ + # extend pwell over the read transistors to the height of the bitcell if(self.num_read > 0): # calculate the edge of the read transistor well clostest to the center left_read_well_xpos = self.read_nmos_left[0].offset.x + drc["well_enclosure_active"] @@ -997,7 +1075,7 @@ class pbitcell(pgate.pgate): width=read_well_width, height=read_well_height) - """ extend nwell to encompass inverter_pmos """ + # extend nwell to encompass inverter_pmos # calculate offset of the left pmos well inverter_well_xpos = -self.inverter_tile_width - drc["well_enclosure_active"] inverter_well_ypos = self.inverter_nmos.active_height + self.inverter_gap - drc["well_enclosure_active"] @@ -1014,7 +1092,7 @@ class pbitcell(pgate.pgate): height=well_height) - """ add well contacts """ + # add well contacts # connect pimplants to gnd offset = vector(0, self.gnd_position.y + 0.5*contact.well.second_layer_width) self.add_contact_center(layers=("active", "contact", "metal1"), diff --git a/compiler/pgates/single_level_column_mux.py b/compiler/pgates/single_level_column_mux.py index c4deedb8..604c9312 100644 --- a/compiler/pgates/single_level_column_mux.py +++ b/compiler/pgates/single_level_column_mux.py @@ -17,21 +17,19 @@ class single_level_column_mux(design.design): design.design.__init__(self, name) debug.info(2, "create single column mux cell: {0}".format(name)) - from importlib import reload - c = reload(__import__(OPTS.bitcell)) - self.mod_bitcell = getattr(c, OPTS.bitcell) - self.bitcell = self.mod_bitcell() - - self.ptx_width = tx_size * drc["minwidth_tx"] + self.tx_size = tx_size self.create_netlist() - self.create_layout() + if not OPTS.netlist_only: + self.create_layout() def create_netlist(self): - self.add_pin_list(["bl", "br", "bl_out", "br_out", "sel", "gnd"]) + self.add_modules() + self.add_pins() self.add_ptx() def create_layout(self): + self.pin_height = 2*self.m2_width self.width = self.bitcell.width self.height = self.nmos_upper.uy() + self.pin_height @@ -39,7 +37,23 @@ class single_level_column_mux(design.design): self.add_bitline_pins() self.connect_bitlines() self.add_wells() + + def add_modules(self): + from importlib import reload + c = reload(__import__(OPTS.bitcell)) + self.mod_bitcell = getattr(c, OPTS.bitcell) + self.bitcell = self.mod_bitcell() + + # Adds nmos_lower,nmos_upper to the module + self.ptx_width = self.tx_size * drc["minwidth_tx"] + self.nmos = ptx(width=self.ptx_width) + self.add_mod(self.nmos) + + + def add_pins(self): + self.add_pin_list(["bl", "br", "bl_out", "br_out", "sel", "gnd"]) + def add_bitline_pins(self): """ Add the top and bottom pins to this cell """ @@ -70,10 +84,6 @@ class single_level_column_mux(design.design): def add_ptx(self): """ Create the two pass gate NMOS transistors to switch the bitlines""" - # Adds nmos_lower,nmos_upper to the module - self.nmos = ptx(width=self.ptx_width) - self.add_mod(self.nmos) - # Space it in the center nmos_lower_position = self.nmos.active_offset.scale(0,1) + vector(0.5*self.bitcell.width-0.5*self.nmos.active_width,0) self.nmos_lower=self.add_inst(name="mux_tx1", diff --git a/compiler/tests/04_pbitcell_test.py b/compiler/tests/04_pbitcell_test.py index 15b64f93..2084c4ab 100755 --- a/compiler/tests/04_pbitcell_test.py +++ b/compiler/tests/04_pbitcell_test.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2.7 +#!/usr/bin/env python3 """ Run regresion tests on a parameterized bitcell """