From 3fb2b9c1c36bd27a7dd157c9dfad759ff64e9d0c Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Mon, 27 Jan 2020 11:53:29 +0100 Subject: [PATCH 1/5] Bitcell arrays: Create abstract base class a lot of functions of dummy- and bitcell-array are either copy-pasted or have just slight differences. Merge all of those into an abstract base class such that we don't have too much duplicate code. Signed-off-by: Bastian Koppelmann --- compiler/modules/base_array.py | 107 ++++++++++++++++++++++++++++++ compiler/modules/bitcell_array.py | 91 ++----------------------- compiler/modules/dummy_array.py | 94 ++------------------------ 3 files changed, 115 insertions(+), 177 deletions(-) create mode 100644 compiler/modules/base_array.py diff --git a/compiler/modules/base_array.py b/compiler/modules/base_array.py new file mode 100644 index 00000000..db2b1be6 --- /dev/null +++ b/compiler/modules/base_array.py @@ -0,0 +1,107 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2019 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import debug +import design + +class bitcell_base_array(design.design): + """ + Abstract base class for bitcell-arrays -- bitcell, dummy + """ + def __init__(self, cols, rows, name): + design.design.__init__(self, name) + debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols)) + self.add_comment("rows: {0} cols: {1}".format(rows, cols)) + + self.column_size = cols + self.row_size = rows + + def add_pins(self): + row_list = self.cell.get_all_wl_names() + column_list = self.cell.get_all_bitline_names() + for col in range(self.column_size): + for cell_column in column_list: + self.add_pin(cell_column+"_{0}".format(col), "INOUT") + for row in range(self.row_size): + for cell_row in row_list: + self.add_pin(cell_row+"_{0}".format(row), "INPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") + + def get_bitcell_pins(self, col, row): + """ Creates a list of connections in the bitcell, + indexed by column and row, for instance use in bitcell_array """ + + bitcell_pins = [] + + pin_names = self.cell.get_all_bitline_names() + for pin in pin_names: + bitcell_pins.append(pin+"_{0}".format(col)) + pin_names = self.cell.get_all_wl_names() + for pin in pin_names: + bitcell_pins.append(pin+"_{0}".format(row)) + bitcell_pins.append("vdd") + bitcell_pins.append("gnd") + + return bitcell_pins + + def add_layout_pins(self): + """ Add the layout pins """ + + row_list = self.cell.get_all_wl_names() + column_list = self.cell.get_all_bitline_names() + + for col in range(self.column_size): + for cell_column in column_list: + bl_pin = self.cell_inst[0,col].get_pin(cell_column) + self.add_layout_pin(text=cell_column+"_{0}".format(col), + layer=bl_pin.layer, + offset=bl_pin.ll().scale(1,0), + width=bl_pin.width(), + height=self.height) + + for row in range(self.row_size): + for cell_row in row_list: + wl_pin = self.cell_inst[row,0].get_pin(cell_row) + self.add_layout_pin(text=cell_row+"_{0}".format(row), + layer=wl_pin.layer, + offset=wl_pin.ll().scale(0,1), + width=self.width, + height=wl_pin.height()) + + # For every second row and column, add a via for gnd and vdd + for row in range(self.row_size): + for col in range(self.column_size): + inst = self.cell_inst[row,col] + for pin_name in ["vdd", "gnd"]: + for pin in inst.get_pins(pin_name): + self.add_power_pin(name=pin_name, loc=pin.center(), vertical=True, start_layer=pin.layer) + + + + def place_array(self, name_template, row_offset=0): + # We increase it by a well enclosure so the precharges don't overlap our wells + self.height = self.row_size*self.cell.height + self.width = self.column_size*self.cell.width + + xoffset = 0.0 + for col in range(self.column_size): + yoffset = 0.0 + for row in range(self.row_size): + name = name_template.format(row, col) + + if (row + row_offset) % 2: + tempy = yoffset + self.cell.height + dir_key = "MX" + else: + tempy = yoffset + dir_key = "" + + self.cell_inst[row,col].place(offset=[xoffset, tempy], + mirror=dir_key) + yoffset += self.cell.height + xoffset += self.cell.width diff --git a/compiler/modules/bitcell_array.py b/compiler/modules/bitcell_array.py index bf43736b..4c1c798b 100644 --- a/compiler/modules/bitcell_array.py +++ b/compiler/modules/bitcell_array.py @@ -7,25 +7,21 @@ # import debug import design +from base_array import bitcell_base_array from tech import drc, spice from vector import vector from globals import OPTS from sram_factory import factory import logical_effort -class bitcell_array(design.design): +class bitcell_array(bitcell_base_array): """ Creates a rows x cols array of memory cells. Assumes bit-lines and word line is connected by abutment. Connects the word lines and bit lines. """ def __init__(self, cols, rows, name): - design.design.__init__(self, name) - debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols)) - self.add_comment("rows: {0} cols: {1}".format(rows, cols)) - - self.column_size = cols - self.row_size = rows + super().__init__(cols, rows, name) self.create_netlist() if not OPTS.netlist_only: @@ -44,27 +40,7 @@ class bitcell_array(design.design): 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 - self.width = self.column_size*self.cell.width - - xoffset = 0.0 - for col in range(self.column_size): - yoffset = 0.0 - for row in range(self.row_size): - name = "bit_r{0}_c{1}".format(row, col) - - if row % 2: - tempy = yoffset + self.cell.height - dir_key = "MX" - else: - tempy = yoffset - dir_key = "" - - self.cell_inst[row,col].place(offset=[xoffset, tempy], - mirror=dir_key) - yoffset += self.cell.height - xoffset += self.cell.width + self.place_array("bit_r{0}_c{1}") self.add_layout_pins() @@ -72,41 +48,13 @@ class bitcell_array(design.design): self.DRC_LVS() - def add_pins(self): - row_list = self.cell.get_all_wl_names() - column_list = self.cell.get_all_bitline_names() - for col in range(self.column_size): - for cell_column in column_list: - self.add_pin(cell_column+"_{0}".format(col), "INOUT") - for row in range(self.row_size): - for cell_row in row_list: - self.add_pin(cell_row+"_{0}".format(row), "INPUT") - self.add_pin("vdd", "POWER") - self.add_pin("gnd", "GROUND") def add_modules(self): """ Add the modules used in this design """ self.cell = factory.create(module_type="bitcell") self.add_mod(self.cell) - def get_bitcell_pins(self, col, row): - """ Creates a list of connections in the bitcell, - indexed by column and row, for instance use in bitcell_array """ - - bitcell_pins = [] - - pin_names = self.cell.get_all_bitline_names() - for pin in pin_names: - bitcell_pins.append(pin+"_{0}".format(col)) - pin_names = self.cell.get_all_wl_names() - for pin in pin_names: - bitcell_pins.append(pin+"_{0}".format(row)) - bitcell_pins.append("vdd") - bitcell_pins.append("gnd") - - return bitcell_pins - def create_instances(self): """ Create the module instances used in this design """ self.cell_inst = {} @@ -117,37 +65,6 @@ class bitcell_array(design.design): mod=self.cell) self.connect_inst(self.get_bitcell_pins(col, row)) - def add_layout_pins(self): - """ Add the layout pins """ - - row_list = self.cell.get_all_wl_names() - column_list = self.cell.get_all_bitline_names() - - for col in range(self.column_size): - for cell_column in column_list: - bl_pin = self.cell_inst[0,col].get_pin(cell_column) - self.add_layout_pin(text=cell_column+"_{0}".format(col), - layer=bl_pin.layer, - offset=bl_pin.ll().scale(1,0), - width=bl_pin.width(), - height=self.height) - - for row in range(self.row_size): - for cell_row in row_list: - wl_pin = self.cell_inst[row,0].get_pin(cell_row) - self.add_layout_pin(text=cell_row+"_{0}".format(row), - layer=wl_pin.layer, - offset=wl_pin.ll().scale(0,1), - width=self.width, - height=wl_pin.height()) - - # For every second row and column, add a via for gnd and vdd - for row in range(self.row_size): - for col in range(self.column_size): - inst = self.cell_inst[row,col] - for pin_name in ["vdd", "gnd"]: - for pin in inst.get_pins(pin_name): - self.add_power_pin(name=pin_name, loc=pin.center(), vertical=True, start_layer=pin.layer) def analytical_power(self, corner, load): """Power of Bitcell array and bitline in nW.""" diff --git a/compiler/modules/dummy_array.py b/compiler/modules/dummy_array.py index 1e5a2121..88717b56 100644 --- a/compiler/modules/dummy_array.py +++ b/compiler/modules/dummy_array.py @@ -5,23 +5,19 @@ # import debug import design +from base_array import bitcell_base_array from tech import drc import contact from sram_factory import factory from vector import vector from globals import OPTS -class dummy_array(design.design): +class dummy_array(bitcell_base_array): """ Generate a dummy row/column for the replica array. """ def __init__(self, cols, rows, mirror=0, name=""): - design.design.__init__(self, name) - debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols)) - self.add_comment("rows: {0} cols: {1}".format(rows, cols)) - - self.column_size = cols - self.row_size = rows + super().__init__(cols, rows, name) self.mirror = mirror self.create_netlist() @@ -37,27 +33,7 @@ class dummy_array(design.design): 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.dummy_cell.height - self.width = self.column_size*self.dummy_cell.width - - xoffset = 0.0 - for col in range(self.column_size): - yoffset = 0.0 - for row in range(self.row_size): - name = "dummy_r{0}_c{1}".format(row, col) - - if (row+self.mirror) % 2: - tempy = yoffset + self.dummy_cell.height - dir_key = "MX" - else: - tempy = yoffset - dir_key = "" - - self.cell_inst[row,col].place(offset=[xoffset, tempy], - mirror=dir_key) - yoffset += self.dummy_cell.height - xoffset += self.dummy_cell.width + self.place_array("dummy_r{0}_c{1}", self.mirror) self.add_layout_pins() @@ -65,18 +41,6 @@ class dummy_array(design.design): self.DRC_LVS() - def add_pins(self): - row_list = self.cell.get_all_wl_names() - column_list = self.cell.get_all_bitline_names() - for col in range(self.column_size): - for cell_column in column_list: - self.add_pin(cell_column+"_{0}".format(col), "INOUT") - for row in range(self.row_size): - for cell_row in row_list: - self.add_pin(cell_row+"_{0}".format(row), "INPUT") - self.add_pin("vdd", "POWER") - self.add_pin("gnd", "GROUND") - def add_modules(self): """ Add the modules used in this design """ self.dummy_cell = factory.create(module_type="dummy_bitcell") @@ -84,23 +48,6 @@ class dummy_array(design.design): self.cell = factory.create(module_type="bitcell") - def get_bitcell_pins(self, col, row): - """ Creates a list of connections in the bitcell, - indexed by column and row, for instance use in bitcell_array """ - - bitcell_pins = [] - - pin_names = self.cell.get_all_bitline_names() - for pin in pin_names: - bitcell_pins.append(pin+"_{0}".format(col)) - pin_names = self.cell.get_all_wl_names() - for pin in pin_names: - bitcell_pins.append(pin+"_{0}".format(row)) - bitcell_pins.append("vdd") - bitcell_pins.append("gnd") - - return bitcell_pins - def create_instances(self): """ Create the module instances used in this design """ @@ -111,39 +58,6 @@ class dummy_array(design.design): self.cell_inst[row,col]=self.add_inst(name=name, mod=self.dummy_cell) self.connect_inst(self.get_bitcell_pins(col, row)) - - def add_layout_pins(self): - """ Add the layout pins """ - - row_list = self.cell.get_all_wl_names() - column_list = self.cell.get_all_bitline_names() - - for col in range(self.column_size): - for cell_column in column_list: - bl_pin = self.cell_inst[0,col].get_pin(cell_column) - self.add_layout_pin(text=cell_column+"_{0}".format(col), - layer="m2", - offset=bl_pin.ll(), - width=bl_pin.width(), - height=self.height) - - for row in range(self.row_size): - for cell_row in row_list: - wl_pin = self.cell_inst[row,0].get_pin(cell_row) - self.add_layout_pin(text=cell_row+"_{0}".format(row), - layer="m1", - offset=wl_pin.ll(), - width=self.width, - height=wl_pin.height()) - - # For every second row and column, add a via for gnd and vdd - for row in range(self.row_size): - for col in range(self.column_size): - inst = self.cell_inst[row,col] - for pin_name in ["vdd", "gnd"]: - for pin in inst.get_pins(pin_name): - self.add_power_pin(name=pin_name, loc=pin.center(), vertical=True, start_layer=pin.layer) - def input_load(self): wl_wire = self.gen_wl_wire() From df9f351a915d1af4bb77322c98514dbc5a59b5f1 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Tue, 28 Jan 2020 11:03:08 +0100 Subject: [PATCH 2/5] Add custom cell properties to technologies this is technology specific database to store data about the custom design cells. For now it only contains on which axis the bitcells are mirrored. This is a first step to support thin cells that need to be mirrored on the x and y axis. Signed-off-by: Bastian Koppelmann --- compiler/modules/base_array.py | 4 ++-- compiler/modules/custom_cell_properties.py | 28 ++++++++++++++++++++++ compiler/modules/replica_column.py | 4 ++-- technology/freepdk45/tech/tech.py | 7 ++++++ technology/scn3me_subm/tech/tech.py | 8 +++++++ technology/scn4m_subm/tech/tech.py | 7 ++++++ 6 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 compiler/modules/custom_cell_properties.py diff --git a/compiler/modules/base_array.py b/compiler/modules/base_array.py index db2b1be6..40481c59 100644 --- a/compiler/modules/base_array.py +++ b/compiler/modules/base_array.py @@ -7,6 +7,7 @@ # import debug import design +from tech import cell_properties class bitcell_base_array(design.design): """ @@ -93,8 +94,7 @@ class bitcell_base_array(design.design): yoffset = 0.0 for row in range(self.row_size): name = name_template.format(row, col) - - if (row + row_offset) % 2: + if cell_properties.bitcell.mirror.x and (row + row_offset) % 2: tempy = yoffset + self.cell.height dir_key = "MX" else: diff --git a/compiler/modules/custom_cell_properties.py b/compiler/modules/custom_cell_properties.py new file mode 100644 index 00000000..085527fc --- /dev/null +++ b/compiler/modules/custom_cell_properties.py @@ -0,0 +1,28 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2020 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# + +class _MirrorAxis: + def __init__(self, x, y): + self.x = x + self.y = y + +class _Bitcell: + def __init__(self, mirror): + self.mirror = mirror + +class CellProperties(): + """ + TODO + """ + def __init__(self): + self.names = {} + self._bitcell = _Bitcell(_MirrorAxis(True, False)) + + @property + def bitcell(self): + return self._bitcell diff --git a/compiler/modules/replica_column.py b/compiler/modules/replica_column.py index 5552ed55..283787c2 100644 --- a/compiler/modules/replica_column.py +++ b/compiler/modules/replica_column.py @@ -92,7 +92,7 @@ class replica_column(design.design): self.connect_inst(self.get_bitcell_pins(0, row)) def place_instances(self): - + from tech import cell_properties # Flip the mirrors if we have an odd number of replica+dummy rows at the bottom # so that we will start with mirroring rather than not mirroring rbl_offset = (self.left_rbl+1)%2 @@ -100,7 +100,7 @@ class replica_column(design.design): for row in range(self.total_size): name = "bit_r{0}_{1}".format(row,"rbl") offset = vector(0,self.cell.height*(row+(row+rbl_offset)%2)) - if (row+rbl_offset)%2: + if cell_properties.bitcell.mirror.x and (row+rbl_offset)%2: dir_key = "MX" else: dir_key = "R0" diff --git a/technology/freepdk45/tech/tech.py b/technology/freepdk45/tech/tech.py index 8b769af9..c21b1f97 100644 --- a/technology/freepdk45/tech/tech.py +++ b/technology/freepdk45/tech/tech.py @@ -8,6 +8,7 @@ import os from design_rules import * from module_type import * +from custom_cell_properties import CellProperties """ File containing the process technology parameters for FreePDK 45nm. @@ -24,6 +25,12 @@ File containing the process technology parameters for FreePDK 45nm. # For example: tech_modules['contact'] = 'contact_freepdk45' tech_modules = ModuleType() +################################################### +# Custom cell properties +################################################### +cell_properties = CellProperties() +cell_properties.bitcell.mirror.x = True +cell_properties.bitcell.mirror.y = False ################################################### # GDS file info diff --git a/technology/scn3me_subm/tech/tech.py b/technology/scn3me_subm/tech/tech.py index cb476df5..9e6f370b 100755 --- a/technology/scn3me_subm/tech/tech.py +++ b/technology/scn3me_subm/tech/tech.py @@ -1,6 +1,7 @@ import os from design_rules import * from module_type import * +from custom_cell_properties import CellProperties """ File containing the process technology parameters for SCMOS 3me, subm, 180nm. @@ -12,6 +13,13 @@ File containing the process technology parameters for SCMOS 3me, subm, 180nm. # For example: tech_modules['contact'] = 'contact_scn3me' tech_modules = ModuleType() +################################################### +# Custom cell properties +################################################### +cell_properties = CellProperties() +cell_properties.bitcell.mirror.x = True +cell_properties.bitcell.mirror.y = False + #GDS file info GDS={} # gds units diff --git a/technology/scn4m_subm/tech/tech.py b/technology/scn4m_subm/tech/tech.py index 3000dc99..ce89e5af 100644 --- a/technology/scn4m_subm/tech/tech.py +++ b/technology/scn4m_subm/tech/tech.py @@ -8,6 +8,7 @@ import os from design_rules import * from module_type import * +from custom_cell_properties import CellProperties """ File containing the process technology parameters for SCMOS 4m, 0.35um @@ -24,6 +25,12 @@ File containing the process technology parameters for SCMOS 4m, 0.35um # For example: tech_modules['contact'] = 'contact_scn4m' tech_modules = ModuleType() +################################################### +# Custom cell properties +################################################### +cell_properties = CellProperties() +cell_properties.bitcell.mirror.x = True +cell_properties.bitcell.mirror.y = False ################################################### # GDS file info From dd1afe03133d70254711574152ff519e8a8f67a6 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Mon, 27 Jan 2020 17:17:06 +0100 Subject: [PATCH 3/5] Bitcell arrays: Allow mirroring on the y axis this allows for bitcells that need to be mirrored on the y axis, like thin cells. However, the portdata elements also need to be mirrored on the y axis. Otherwise the router will fail horribly when connecting bitlines. Signed-off-by: Bastian Koppelmann --- compiler/modules/base_array.py | 34 +++++++++++++++++---- compiler/modules/bitcell_array.py | 4 +-- compiler/modules/dummy_array.py | 4 +-- compiler/modules/replica_bitcell_array.py | 36 ++++++++++++++++++----- compiler/modules/replica_column.py | 27 ++++++++++++++--- 5 files changed, 84 insertions(+), 21 deletions(-) diff --git a/compiler/modules/base_array.py b/compiler/modules/base_array.py index 40481c59..08a52c21 100644 --- a/compiler/modules/base_array.py +++ b/compiler/modules/base_array.py @@ -13,13 +13,14 @@ class bitcell_base_array(design.design): """ Abstract base class for bitcell-arrays -- bitcell, dummy """ - def __init__(self, cols, rows, name): + def __init__(self, cols, rows, name, column_offset): design.design.__init__(self, name) debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols)) self.add_comment("rows: {0} cols: {1}".format(rows, cols)) self.column_size = cols self.row_size = rows + self.column_offset = column_offset def add_pins(self): row_list = self.cell.get_all_wl_names() @@ -82,6 +83,23 @@ class bitcell_base_array(design.design): for pin in inst.get_pins(pin_name): self.add_power_pin(name=pin_name, loc=pin.center(), vertical=True, start_layer=pin.layer) + def _adjust_x_offset(self, xoffset, col, col_offset): + tempx = xoffset + dir_y = False + # If we mirror the current cell on the y axis adjust the x position + if cell_properties.bitcell.mirror.y and (col + col_offset) % 2: + tempx = xoffset + self.cell.width + dir_y = True + return (tempx, dir_y) + + def _adjust_y_offset(self, yoffset, row, row_offset): + tempy = yoffset + dir_x = False + # If we mirror the current cell on the x axis adjust the y position + if cell_properties.bitcell.mirror.x and (row + row_offset) % 2: + tempy = yoffset + self.cell.height + dir_x = True + return (tempy, dir_x) def place_array(self, name_template, row_offset=0): @@ -92,16 +110,22 @@ class bitcell_base_array(design.design): xoffset = 0.0 for col in range(self.column_size): yoffset = 0.0 + tempx, dir_y = self._adjust_x_offset(xoffset, col, self.column_offset) + for row in range(self.row_size): name = name_template.format(row, col) - if cell_properties.bitcell.mirror.x and (row + row_offset) % 2: - tempy = yoffset + self.cell.height + tempy, dir_x = self._adjust_y_offset(yoffset, row, row_offset) + + if dir_x and dir_y: + dir_key = "XY" + elif dir_x: dir_key = "MX" + elif dir_y: + dir_key = "MY" else: - tempy = yoffset dir_key = "" - self.cell_inst[row,col].place(offset=[xoffset, tempy], + self.cell_inst[row,col].place(offset=[tempx, tempy], mirror=dir_key) yoffset += self.cell.height xoffset += self.cell.width diff --git a/compiler/modules/bitcell_array.py b/compiler/modules/bitcell_array.py index 4c1c798b..636408df 100644 --- a/compiler/modules/bitcell_array.py +++ b/compiler/modules/bitcell_array.py @@ -20,8 +20,8 @@ class bitcell_array(bitcell_base_array): and word line is connected by abutment. Connects the word lines and bit lines. """ - def __init__(self, cols, rows, name): - super().__init__(cols, rows, name) + def __init__(self, cols, rows, name, column_offset=0): + super().__init__(cols, rows, name, column_offset) self.create_netlist() if not OPTS.netlist_only: diff --git a/compiler/modules/dummy_array.py b/compiler/modules/dummy_array.py index 88717b56..997330e1 100644 --- a/compiler/modules/dummy_array.py +++ b/compiler/modules/dummy_array.py @@ -16,8 +16,8 @@ class dummy_array(bitcell_base_array): """ Generate a dummy row/column for the replica array. """ - def __init__(self, cols, rows, mirror=0, name=""): - super().__init__(cols, rows, name) + def __init__(self, cols, rows, column_offset=0, mirror=0, name=""): + super().__init__(cols, rows, name, column_offset) self.mirror = mirror self.create_netlist() diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 74962ba2..9cf5c5a2 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -86,6 +86,7 @@ class replica_bitcell_array(design.design): # Bitcell array self.bitcell_array = factory.create(module_type="bitcell_array", + column_offset=1 + self.left_rbl, cols=self.column_size, rows=self.row_size) self.add_mod(self.bitcell_array) @@ -95,12 +96,17 @@ class replica_bitcell_array(design.design): for bit in range(self.left_rbl+self.right_rbl): if bit=self.total_size-right_rbl-1, @@ -96,14 +98,31 @@ class replica_column(design.design): # Flip the mirrors if we have an odd number of replica+dummy rows at the bottom # so that we will start with mirroring rather than not mirroring rbl_offset = (self.left_rbl+1)%2 - + + # if our bitcells are mirrored on the y axis, check if we are in global + # column that needs to be flipped. + dir_y = False + xoffset = 0 + if cell_properties.bitcell.mirror.y and self.column_offset % 2: + dir_y = True + xoffset = self.replica_cell.width + for row in range(self.total_size): + dir_x = False name = "bit_r{0}_{1}".format(row,"rbl") - offset = vector(0,self.cell.height*(row+(row+rbl_offset)%2)) if cell_properties.bitcell.mirror.x and (row+rbl_offset)%2: + dir_x = True + + offset = vector(xoffset,self.cell.height*(row+(row+rbl_offset)%2)) + + if dir_x and dir_y: + dir_key = "XY" + elif dir_x: dir_key = "MX" + elif dir_y: + dir_key = "MY" else: - dir_key = "R0" + dir_key = "" self.cell_inst[row].place(offset=offset, mirror=dir_key) From ed66fca031d0af78883b0348e845dac20e1e0b25 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Mon, 27 Jan 2020 17:20:48 +0100 Subject: [PATCH 4/5] write_driver/sense_amp/precharge arrays: Allow y axis mirroring since the bitlines alternate in the bitcell array we also need to mirror the port_data elements. Signed-off-by: Bastian Koppelmann --- compiler/modules/precharge_array.py | 14 ++++++++++++-- compiler/modules/sense_amp_array.py | 19 ++++++++++++++++--- compiler/modules/write_driver_array.py | 13 +++++++++++-- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/compiler/modules/precharge_array.py b/compiler/modules/precharge_array.py index c2617f50..54ed2690 100644 --- a/compiler/modules/precharge_array.py +++ b/compiler/modules/precharge_array.py @@ -107,9 +107,19 @@ class precharge_array(design.design): def place_insts(self): """ Places precharge array by horizontally tiling the precharge cell""" + from tech import cell_properties + xoffset = 0 for i in range(self.columns): - offset = vector(self.pc_cell.width * i, 0) - self.local_insts[i].place(offset) + tempx = xoffset + if cell_properties.bitcell.mirror.y and (i + 1) % 2: + mirror = "MY" + tempx = tempx + self.pc_cell.width + else: + mirror = "" + + offset = vector(tempx, 0) + self.local_insts[i].place(offset=offset, mirror=mirror) + xoffset = xoffset + self.pc_cell.width def get_en_cin(self): """Get the relative capacitance of all the clk connections in the precharge array""" diff --git a/compiler/modules/sense_amp_array.py b/compiler/modules/sense_amp_array.py index 2447e4b8..fcb68792 100644 --- a/compiler/modules/sense_amp_array.py +++ b/compiler/modules/sense_amp_array.py @@ -84,14 +84,27 @@ class sense_amp_array(design.design): "en", "vdd", "gnd"]) def place_sense_amp_array(self): - + from tech import cell_properties if self.bitcell.width > self.amp.width: amp_spacing = self.bitcell.width * self.words_per_row else: amp_spacing = self.amp.width * self.words_per_row + for i in range(0,self.word_size): - amp_position = vector(amp_spacing * i, 0) - self.local_insts[i].place(amp_position) + xoffset = amp_spacing * i + + # align the xoffset to the grid of bitcells. This way we + # know when to do the mirroring. + grid_x = int(xoffset / self.amp.width) + + if cell_properties.bitcell.mirror.y and grid_x % 2: + mirror = "MY" + xoffset = xoffset + self.amp.width + else: + mirror = "" + + amp_position = vector(xoffset, 0) + self.local_insts[i].place(offset=amp_position,mirror=mirror) def add_layout_pins(self): diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index ac4dab00..cac9b396 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -106,14 +106,23 @@ class write_driver_array(design.design): def place_write_array(self): + from tech import cell_properties if self.bitcell.width > self.driver.width: self.driver_spacing = self.bitcell.width else: self.driver_spacing = self.driver.width for i in range(0,self.columns,self.words_per_row): index = int(i/self.words_per_row) - base = vector(i * self.driver_spacing, 0) - self.driver_insts[index].place(base) + xoffset = i * self.driver_spacing + + if cell_properties.bitcell.mirror.y and i % 2: + mirror = "MY" + xoffset = xoffset + self.driver.width + else: + mirror = "" + + base = vector(xoffset, 0) + self.driver_insts[index].place(offset=base, mirror=mirror) def add_layout_pins(self): From b5701af8645118aefb58195079d57379dd72d664 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Mon, 27 Jan 2020 17:23:01 +0100 Subject: [PATCH 5/5] column_mux: Allow y axis mirroring since the bitlines alternate in the bitcell array we also need to mirror the port_data elements. Signed-off-by: Bastian Koppelmann --- .../modules/single_level_column_mux_array.py | 40 +++++++++++++++---- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/compiler/modules/single_level_column_mux_array.py b/compiler/modules/single_level_column_mux_array.py index 09f21cfa..24510015 100644 --- a/compiler/modules/single_level_column_mux_array.py +++ b/compiler/modules/single_level_column_mux_array.py @@ -99,11 +99,19 @@ class single_level_column_mux_array(design.design): "gnd"]) def place_array(self): + from tech import cell_properties # For every column, add a pass gate for col_num in range(self.columns): + xoffset = col_num * self.mux.width + if cell_properties.bitcell.mirror.y and col_num % 2: + mirror = "MY" + xoffset = xoffset + self.mux.width + else: + mirror = "" + name = "XMUX{0}".format(col_num) - x_off = vector(col_num * self.mux.width, self.route_height) - self.mux_inst[col_num].place(x_off) + offset = vector(xoffset, self.route_height) + self.mux_inst[col_num].place(offset=offset, mirror=mirror) def add_layout_pins(self): @@ -161,6 +169,7 @@ class single_level_column_mux_array(design.design): def route_bitlines(self): """ Connect the output bit-lines to form the appropriate width mux """ + from tech import cell_properties for j in range(self.columns): bl_offset = self.mux_inst[j].get_pin("bl_out").bc() br_offset = self.mux_inst[j].get_pin("br_out").bc() @@ -171,23 +180,38 @@ class single_level_column_mux_array(design.design): bl_out_offset_end = bl_out_offset + vector(0,self.route_height) br_out_offset_end = br_out_offset + vector(0,self.route_height) + if cell_properties.bitcell.mirror.y and j % 2: + tmp_bl_out_end = br_out_offset_end + tmp_br_out_end = bl_out_offset_end + else: + tmp_bl_out_end = bl_out_offset_end + tmp_br_out_end = br_out_offset_end + if (j % self.words_per_row) == 0: # Create the metal1 to connect the n-way mux output from the pass gate # These will be located below the select lines. Yes, these are M2 width # to ensure vias are enclosed and M1 min width rules. width = self.m2_width + self.mux.width * (self.words_per_row - 1) - self.add_path("m1", [bl_out_offset, bl_out_offset+vector(width,0)]) - self.add_path("m1", [br_out_offset, br_out_offset+vector(width,0)]) + + if cell_properties.bitcell.mirror.y and (j % 2) == 0: + bl = self.mux.get_pin("bl") + br = self.mux.get_pin("br") + dist = abs(bl.ll().x - br.ll().x) + else: + dist = 0 + + self.add_path("m1", [bl_out_offset, bl_out_offset+vector(width+dist,0)]) + self.add_path("m1", [br_out_offset, br_out_offset+vector(width-dist,0)]) # Extend the bitline output rails and gnd downward on the first bit of each n-way mux self.add_layout_pin_segment_center(text="bl_out_{}".format(int(j/self.words_per_row)), layer="m2", start=bl_out_offset, - end=bl_out_offset_end) + end=tmp_bl_out_end) self.add_layout_pin_segment_center(text="br_out_{}".format(int(j/self.words_per_row)), layer="m2", start=br_out_offset, - end=br_out_offset_end) + end=tmp_br_out_end) # This via is on the right of the wire @@ -200,8 +224,8 @@ class single_level_column_mux_array(design.design): else: - self.add_path("m2", [ bl_out_offset, bl_out_offset_end]) - self.add_path("m2", [ br_out_offset, br_out_offset_end]) + self.add_path("m2", [ bl_out_offset, tmp_bl_out_end]) + self.add_path("m2", [ br_out_offset, tmp_br_out_end]) # This via is on the right of the wire self.add_via_center(layers=self.m1_stack,