mirror of https://github.com/VLSIDA/OpenRAM.git
Finalized separation of netlist/layout creation.
This commit is contained in:
parent
0daad338e4
commit
19d46f5954
|
|
@ -55,18 +55,21 @@ class bank(design.design):
|
||||||
else:
|
else:
|
||||||
self.prefix=""
|
self.prefix=""
|
||||||
|
|
||||||
|
self.create_netlist()
|
||||||
|
self.create_layout()
|
||||||
|
|
||||||
|
|
||||||
|
def create_netlist(self):
|
||||||
self.compute_sizes()
|
self.compute_sizes()
|
||||||
self.add_pins()
|
self.add_pins()
|
||||||
self.create_modules()
|
|
||||||
self.add_modules()
|
self.add_modules()
|
||||||
self.setup_layout_constraints()
|
self.create_modules()
|
||||||
|
|
||||||
# FIXME: Move this to the add modules function
|
|
||||||
self.add_bank_select()
|
|
||||||
|
|
||||||
|
def create_layout(self):
|
||||||
|
self.place_modules()
|
||||||
|
self.setup_routing_constraints()
|
||||||
self.route_layout()
|
self.route_layout()
|
||||||
|
|
||||||
|
|
||||||
# Can remove the following, but it helps for debug!
|
# Can remove the following, but it helps for debug!
|
||||||
#self.add_lvs_correspondence_points()
|
#self.add_lvs_correspondence_points()
|
||||||
|
|
||||||
|
|
@ -117,23 +120,45 @@ class bank(design.design):
|
||||||
|
|
||||||
self.route_vdd_gnd()
|
self.route_vdd_gnd()
|
||||||
|
|
||||||
def add_modules(self):
|
def create_modules(self):
|
||||||
""" Add modules. The order should not matter! """
|
""" Add modules. The order should not matter! """
|
||||||
|
|
||||||
# Above the bitcell array
|
# Above the bitcell array
|
||||||
self.add_bitcell_array()
|
self.create_bitcell_array()
|
||||||
self.add_precharge_array()
|
self.create_precharge_array()
|
||||||
|
|
||||||
# Below the bitcell array
|
# Below the bitcell array
|
||||||
self.add_column_mux_array()
|
self.create_column_mux_array()
|
||||||
self.add_sense_amp_array()
|
self.create_sense_amp_array()
|
||||||
self.add_write_driver_array()
|
self.create_write_driver_array()
|
||||||
|
|
||||||
# To the left of the bitcell array
|
# To the left of the bitcell array
|
||||||
self.add_row_decoder()
|
self.create_row_decoder()
|
||||||
self.add_wordline_driver()
|
self.create_wordline_driver()
|
||||||
self.add_column_decoder()
|
self.create_column_decoder()
|
||||||
|
|
||||||
|
self.create_bank_select()
|
||||||
|
|
||||||
|
|
||||||
|
def place_modules(self):
|
||||||
|
""" Add modules. The order should not matter! """
|
||||||
|
|
||||||
|
# Above the bitcell array
|
||||||
|
self.place_bitcell_array()
|
||||||
|
self.place_precharge_array()
|
||||||
|
|
||||||
|
# Below the bitcell array
|
||||||
|
self.place_column_mux_array()
|
||||||
|
self.place_sense_amp_array()
|
||||||
|
self.place_write_driver_array()
|
||||||
|
|
||||||
|
# To the left of the bitcell array
|
||||||
|
self.place_row_decoder()
|
||||||
|
self.place_wordline_driver()
|
||||||
|
self.place_column_decoder()
|
||||||
|
|
||||||
|
|
||||||
|
self.place_bank_select()
|
||||||
|
|
||||||
def compute_sizes(self):
|
def compute_sizes(self):
|
||||||
""" Computes the required sizes to create the bank """
|
""" Computes the required sizes to create the bank """
|
||||||
|
|
@ -178,7 +203,7 @@ class bank(design.design):
|
||||||
2*self.m2_pitch)
|
2*self.m2_pitch)
|
||||||
|
|
||||||
|
|
||||||
def create_modules(self):
|
def add_modules(self):
|
||||||
""" Create all the modules using the class loader """
|
""" Create all the modules using the class loader """
|
||||||
self.bitcell = self.mod_bitcell()
|
self.bitcell = self.mod_bitcell()
|
||||||
|
|
||||||
|
|
@ -199,9 +224,9 @@ class bank(design.design):
|
||||||
self.total_wl_list = self.bitcell.list_all_wl_names()
|
self.total_wl_list = self.bitcell.list_all_wl_names()
|
||||||
self.total_bitline_list = self.bitcell.list_all_bitline_names()
|
self.total_bitline_list = self.bitcell.list_all_bitline_names()
|
||||||
|
|
||||||
self.precharge_array = [None] * self.total_read
|
self.precharge_array = []
|
||||||
for k in range(self.total_read):
|
for k in range(self.total_read):
|
||||||
self.precharge_array[k] = self.mod_precharge_array(columns=self.num_cols, bitcell_bl=self.read_bl_list[k], bitcell_br=self.read_br_list[k])
|
self.precharge_array.append(self.mod_precharge_array(columns=self.num_cols, bitcell_bl=self.read_bl_list[k], bitcell_br=self.read_br_list[k]))
|
||||||
self.add_mod(self.precharge_array[k])
|
self.add_mod(self.precharge_array[k])
|
||||||
|
|
||||||
if self.col_addr_size > 0:
|
if self.col_addr_size > 0:
|
||||||
|
|
@ -232,12 +257,12 @@ class bank(design.design):
|
||||||
self.add_mod(self.bank_select)
|
self.add_mod(self.bank_select)
|
||||||
|
|
||||||
|
|
||||||
def add_bitcell_array(self):
|
def create_bitcell_array(self):
|
||||||
""" Adding Bitcell Array """
|
""" Creating Bitcell Array """
|
||||||
|
|
||||||
self.bitcell_array_inst=self.add_inst(name="bitcell_array",
|
self.bitcell_array_inst=self.add_inst(name="bitcell_array",
|
||||||
mod=self.bitcell_array,
|
mod=self.bitcell_array)
|
||||||
offset=vector(0,0))
|
|
||||||
|
|
||||||
temp = []
|
temp = []
|
||||||
for col in range(self.num_cols):
|
for col in range(self.num_cols):
|
||||||
|
|
@ -250,19 +275,19 @@ class bank(design.design):
|
||||||
temp.append("gnd")
|
temp.append("gnd")
|
||||||
self.connect_inst(temp)
|
self.connect_inst(temp)
|
||||||
|
|
||||||
|
def place_bitcell_array(self):
|
||||||
|
""" Placing Bitcell Array """
|
||||||
|
self.place_inst(name="bitcell_array",
|
||||||
|
offset=vector(0,0))
|
||||||
|
|
||||||
def add_precharge_array(self):
|
|
||||||
""" Adding Precharge """
|
|
||||||
|
|
||||||
self.precharge_array_inst = [None] * self.total_read
|
def create_precharge_array(self):
|
||||||
|
""" Creating Precharge """
|
||||||
|
|
||||||
|
self.precharge_array_inst = []
|
||||||
for k in range(self.total_read):
|
for k in range(self.total_read):
|
||||||
# The wells must be far enough apart
|
self.precharge_array_inst.append(self.add_inst(name="precharge_array{}".format(k),
|
||||||
# The enclosure is for the well and the spacing is to the bitcell wells
|
mod=self.precharge_array[k]))
|
||||||
y_offset = self.bitcell_array.height + self.m2_gap
|
|
||||||
self.precharge_array_inst[k]=self.add_inst(name="precharge_array{}".format(k),
|
|
||||||
mod=self.precharge_array[k],
|
|
||||||
offset=vector(0,y_offset))
|
|
||||||
temp = []
|
temp = []
|
||||||
for i in range(self.num_cols):
|
for i in range(self.num_cols):
|
||||||
temp.append(self.read_bl_list[k]+"[{0}]".format(i))
|
temp.append(self.read_bl_list[k]+"[{0}]".format(i))
|
||||||
|
|
@ -270,22 +295,27 @@ class bank(design.design):
|
||||||
temp.extend([self.prefix+"clk_buf_bar", "vdd"])
|
temp.extend([self.prefix+"clk_buf_bar", "vdd"])
|
||||||
self.connect_inst(temp)
|
self.connect_inst(temp)
|
||||||
|
|
||||||
def add_column_mux_array(self):
|
def place_precharge_array(self):
|
||||||
""" Adding Column Mux when words_per_row > 1 . """
|
""" Placing Precharge """
|
||||||
|
|
||||||
if self.col_addr_size > 0:
|
# FIXME: place for multiport
|
||||||
self.column_mux_height = self.column_mux_array.height + self.m2_gap
|
for k in range(self.total_read):
|
||||||
else:
|
# The wells must be far enough apart
|
||||||
self.column_mux_height = 0
|
# The enclosure is for the well and the spacing is to the bitcell wells
|
||||||
|
y_offset = self.bitcell_array.height + self.m2_gap
|
||||||
|
self.place_inst(name=self.precharge_array_inst[k].name,
|
||||||
|
offset=vector(0,y_offset))
|
||||||
|
|
||||||
|
def create_column_mux_array(self):
|
||||||
|
""" Creating Column Mux when words_per_row > 1 . """
|
||||||
|
if self.col_addr_size == 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.col_mux_array_inst = [None] * self.total_ports
|
self.col_mux_array_inst = []
|
||||||
|
|
||||||
for k in range(self.total_ports):
|
for k in range(self.total_ports):
|
||||||
y_offset = self.column_mux_height
|
self.col_mux_array_inst.append(self.add_inst(name="column_mux_array{}".format(k),
|
||||||
self.col_mux_array_inst[k]=self.add_inst(name="column_mux_array{}".format(k),
|
mod=self.column_mux_array))
|
||||||
mod=self.column_mux_array,
|
|
||||||
offset=vector(0,y_offset).scale(-1,-1))
|
|
||||||
temp = []
|
temp = []
|
||||||
for i in range(self.num_cols):
|
for i in range(self.num_cols):
|
||||||
temp.append(self.total_bl_list[k]+"[{0}]".format(i))
|
temp.append(self.total_bl_list[k]+"[{0}]".format(i))
|
||||||
|
|
@ -298,16 +328,27 @@ class bank(design.design):
|
||||||
temp.append("gnd")
|
temp.append("gnd")
|
||||||
self.connect_inst(temp)
|
self.connect_inst(temp)
|
||||||
|
|
||||||
def add_sense_amp_array(self):
|
def place_column_mux_array(self):
|
||||||
""" Adding Sense amp """
|
""" Placing Column Mux when words_per_row > 1 . """
|
||||||
|
if self.col_addr_size > 0:
|
||||||
|
self.column_mux_height = self.column_mux_array.height + self.m2_gap
|
||||||
|
else:
|
||||||
|
self.column_mux_height = 0
|
||||||
|
return
|
||||||
|
|
||||||
self.sense_amp_array_inst = [None] * self.total_read
|
for k in range(self.total_ports):
|
||||||
|
y_offset = self.column_mux_height
|
||||||
for k in range(self.total_read):
|
self.place_inst(name=self.col_mux_array_inst[k].name,
|
||||||
y_offset = self.column_mux_height + self.sense_amp_array.height + self.m2_gap
|
|
||||||
self.sense_amp_array_inst[k]=self.add_inst(name="sense_amp_array{}".format(k),
|
|
||||||
mod=self.sense_amp_array,
|
|
||||||
offset=vector(0,y_offset).scale(-1,-1))
|
offset=vector(0,y_offset).scale(-1,-1))
|
||||||
|
|
||||||
|
def create_sense_amp_array(self):
|
||||||
|
""" Creating Sense amp """
|
||||||
|
|
||||||
|
self.sense_amp_array_inst = []
|
||||||
|
for k in range(self.total_read):
|
||||||
|
self.sense_amp_array_inst.append(self.add_inst(name="sense_amp_array{}".format(k),
|
||||||
|
mod=self.sense_amp_array))
|
||||||
|
|
||||||
temp = []
|
temp = []
|
||||||
for i in range(self.word_size):
|
for i in range(self.word_size):
|
||||||
temp.append("dout{0}[{1}]".format(k,i))
|
temp.append("dout{0}[{1}]".format(k,i))
|
||||||
|
|
@ -321,18 +362,23 @@ class bank(design.design):
|
||||||
temp.extend([self.prefix+"s_en{0}".format(k), "vdd", "gnd"])
|
temp.extend([self.prefix+"s_en{0}".format(k), "vdd", "gnd"])
|
||||||
self.connect_inst(temp)
|
self.connect_inst(temp)
|
||||||
|
|
||||||
def add_write_driver_array(self):
|
def place_sense_amp_array(self):
|
||||||
""" Adding Write Driver """
|
""" Placing Sense amp """
|
||||||
|
|
||||||
self.write_driver_array_inst = [None] * self.total_write
|
# FIXME: place for multiport
|
||||||
|
for k in range(self.total_read):
|
||||||
for k in range(self.total_write):
|
y_offset = self.column_mux_height + self.sense_amp_array.height + self.m2_gap
|
||||||
y_offset = self.sense_amp_array.height + self.column_mux_height \
|
self.place_inst(name=self.sense_amp_array_inst[k].name,
|
||||||
+ self.m2_gap + self.write_driver_array.height
|
|
||||||
self.write_driver_array_inst[k]=self.add_inst(name="write_driver_array{}".format(k),
|
|
||||||
mod=self.write_driver_array,
|
|
||||||
offset=vector(0,y_offset).scale(-1,-1))
|
offset=vector(0,y_offset).scale(-1,-1))
|
||||||
|
|
||||||
|
def create_write_driver_array(self):
|
||||||
|
""" Creating Write Driver """
|
||||||
|
|
||||||
|
self.write_driver_array_inst = []
|
||||||
|
for k in range(self.total_write):
|
||||||
|
self.write_driver_array_inst.append(self.add_inst(name="write_driver_array{}".format(k),
|
||||||
|
mod=self.write_driver_array))
|
||||||
|
|
||||||
temp = []
|
temp = []
|
||||||
for i in range(self.word_size):
|
for i in range(self.word_size):
|
||||||
temp.append("din{0}[{1}]".format(k,i))
|
temp.append("din{0}[{1}]".format(k,i))
|
||||||
|
|
@ -346,23 +392,25 @@ class bank(design.design):
|
||||||
temp.extend([self.prefix+"w_en{0}".format(k), "vdd", "gnd"])
|
temp.extend([self.prefix+"w_en{0}".format(k), "vdd", "gnd"])
|
||||||
self.connect_inst(temp)
|
self.connect_inst(temp)
|
||||||
|
|
||||||
|
def place_write_driver_array(self):
|
||||||
|
""" Placing Write Driver """
|
||||||
|
|
||||||
def add_row_decoder(self):
|
# FIXME: place for multiport
|
||||||
""" Add the hierarchical row decoder """
|
for k in range(self.total_write):
|
||||||
|
y_offset = self.sense_amp_array.height + self.column_mux_height \
|
||||||
|
+ self.m2_gap + self.write_driver_array.height
|
||||||
|
self.place_inst(name=self.write_driver_array_inst[k].name,
|
||||||
|
offset=vector(0,y_offset).scale(-1,-1))
|
||||||
|
|
||||||
# The address and control bus will be in between decoder and the main memory array
|
|
||||||
# This bus will route address bits to the decoder input and column mux inputs.
|
|
||||||
# The wires are actually routed after we placed the stuff on both sides.
|
|
||||||
# The predecoder is below the x-axis and the main decoder is above the x-axis
|
|
||||||
# The address flop and decoder are aligned in the x coord.
|
|
||||||
|
|
||||||
self.row_decoder_inst = [None] * self.total_ports
|
|
||||||
|
|
||||||
|
def create_row_decoder(self):
|
||||||
|
""" Create the hierarchical row decoder """
|
||||||
|
|
||||||
|
self.row_decoder_inst = []
|
||||||
for k in range(self.total_ports):
|
for k in range(self.total_ports):
|
||||||
x_offset = -(self.row_decoder.width + self.central_bus_width + self.wordline_driver.width)
|
self.row_decoder_inst.append(self.add_inst(name="row_decoder{}".format(k),
|
||||||
self.row_decoder_inst[k]=self.add_inst(name="row_decoder{}".format(k),
|
mod=self.row_decoder))
|
||||||
mod=self.row_decoder,
|
|
||||||
offset=vector(x_offset,0))
|
|
||||||
|
|
||||||
temp = []
|
temp = []
|
||||||
for i in range(self.row_addr_size):
|
for i in range(self.row_addr_size):
|
||||||
|
|
@ -372,18 +420,30 @@ class bank(design.design):
|
||||||
temp.extend(["vdd", "gnd"])
|
temp.extend(["vdd", "gnd"])
|
||||||
self.connect_inst(temp)
|
self.connect_inst(temp)
|
||||||
|
|
||||||
def add_wordline_driver(self):
|
def place_row_decoder(self):
|
||||||
""" Wordline Driver """
|
""" Place the hierarchical row decoder """
|
||||||
|
|
||||||
self.wordline_driver_inst = [None] * self.total_ports
|
# The address and control bus will be in between decoder and the main memory array
|
||||||
|
# This bus will route address bits to the decoder input and column mux inputs.
|
||||||
|
# The wires are actually routed after we placed the stuff on both sides.
|
||||||
|
# The predecoder is below the x-axis and the main decoder is above the x-axis
|
||||||
|
# The address flop and decoder are aligned in the x coord.
|
||||||
|
|
||||||
|
# FIXME: place for multiport
|
||||||
for k in range(self.total_ports):
|
for k in range(self.total_ports):
|
||||||
# The wordline driver is placed to the right of the main decoder width.
|
x_offset = -(self.row_decoder.width + self.central_bus_width + self.wordline_driver.width)
|
||||||
x_offset = -(self.central_bus_width + self.wordline_driver.width) + self.m2_pitch
|
self.place_inst(name=self.row_decoder_inst[k].name,
|
||||||
self.wordline_driver_inst[k]=self.add_inst(name="wordline_driver{}".format(k),
|
|
||||||
mod=self.wordline_driver,
|
|
||||||
offset=vector(x_offset,0))
|
offset=vector(x_offset,0))
|
||||||
|
|
||||||
|
|
||||||
|
def create_wordline_driver(self):
|
||||||
|
""" Create the Wordline Driver """
|
||||||
|
|
||||||
|
self.wordline_driver_inst = []
|
||||||
|
for k in range(self.total_ports):
|
||||||
|
self.wordline_driver_inst.append(self.add_inst(name="wordline_driver{}".format(k),
|
||||||
|
mod=self.wordline_driver))
|
||||||
|
|
||||||
temp = []
|
temp = []
|
||||||
for i in range(self.num_rows):
|
for i in range(self.num_rows):
|
||||||
temp.append("dec_out{0}[{1}]".format(k,i))
|
temp.append("dec_out{0}[{1}]".format(k,i))
|
||||||
|
|
@ -394,35 +454,22 @@ class bank(design.design):
|
||||||
temp.append("gnd")
|
temp.append("gnd")
|
||||||
self.connect_inst(temp)
|
self.connect_inst(temp)
|
||||||
|
|
||||||
|
def place_wordline_driver(self):
|
||||||
|
""" Place the Wordline Driver """
|
||||||
|
|
||||||
def add_column_decoder_module(self):
|
# FIXME: place for multiport
|
||||||
|
for k in range(self.total_ports):
|
||||||
|
# The wordline driver is placed to the right of the main decoder width.
|
||||||
|
x_offset = -(self.central_bus_width + self.wordline_driver.width) + self.m2_pitch
|
||||||
|
self.place_inst(name=self.wordline_driver_inst[k].name,
|
||||||
|
offset=vector(x_offset,0))
|
||||||
|
|
||||||
|
|
||||||
|
def create_column_decoder(self):
|
||||||
"""
|
"""
|
||||||
Create a 2:4 or 3:8 column address decoder.
|
Create a 2:4 or 3:8 column address decoder.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.col_decoder_inst = [None] * self.total_ports
|
|
||||||
|
|
||||||
for k in range(self.total_ports):
|
|
||||||
# Place the col decoder right aligned with row decoder
|
|
||||||
x_off = -(self.central_bus_width + self.wordline_driver.width + self.col_decoder.width)
|
|
||||||
y_off = -(self.col_decoder.height + 2*drc["well_to_well"])
|
|
||||||
self.col_decoder_inst[k]=self.add_inst(name="col_address_decoder{}".format(k),
|
|
||||||
mod=self.col_decoder,
|
|
||||||
offset=vector(x_off,y_off))
|
|
||||||
|
|
||||||
temp = []
|
|
||||||
for i in range(self.col_addr_size):
|
|
||||||
temp.append("addr{0}[{1}]".format(k,i))
|
|
||||||
for j in range(self.num_col_addr_lines):
|
|
||||||
temp.append("sel{0}[{1}]".format(k,j))
|
|
||||||
temp.extend(["vdd", "gnd"])
|
|
||||||
self.connect_inst(temp)
|
|
||||||
|
|
||||||
def add_column_decoder(self):
|
|
||||||
"""
|
|
||||||
Create a decoder to decode column select lines. This could be an inverter/buffer for 1:2,
|
|
||||||
2:4 decoder, or 3:8 decoder.
|
|
||||||
"""
|
|
||||||
if self.col_addr_size == 0:
|
if self.col_addr_size == 0:
|
||||||
return
|
return
|
||||||
elif self.col_addr_size == 1:
|
elif self.col_addr_size == 1:
|
||||||
|
|
@ -436,25 +483,45 @@ class bank(design.design):
|
||||||
# No error checking before?
|
# No error checking before?
|
||||||
debug.error("Invalid column decoder?",-1)
|
debug.error("Invalid column decoder?",-1)
|
||||||
|
|
||||||
self.add_column_decoder_module()
|
self.col_decoder_inst = []
|
||||||
|
for k in range(self.total_ports):
|
||||||
|
self.col_decoder_inst.append(self.add_inst(name="col_address_decoder{}".format(k),
|
||||||
|
mod=self.col_decoder))
|
||||||
|
|
||||||
|
temp = []
|
||||||
|
for i in range(self.col_addr_size):
|
||||||
|
temp.append("addr{0}[{1}]".format(k,i))
|
||||||
|
for j in range(self.num_col_addr_lines):
|
||||||
|
temp.append("sel{0}[{1}]".format(k,j))
|
||||||
|
temp.extend(["vdd", "gnd"])
|
||||||
|
self.connect_inst(temp)
|
||||||
|
|
||||||
|
def place_column_decoder(self):
|
||||||
|
"""
|
||||||
|
Place a 2:4 or 3:8 column address decoder.
|
||||||
|
"""
|
||||||
|
if self.col_addr_size == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
# FIXME: place for multiport
|
||||||
|
for k in range(self.total_ports):
|
||||||
|
# Place the col decoder right aligned with row decoder
|
||||||
|
x_off = -(self.central_bus_width + self.wordline_driver.width + self.col_decoder.width)
|
||||||
|
y_off = -(self.col_decoder.height + 2*drc["well_to_well"])
|
||||||
|
self.place_inst(name=self.col_decoder_inst[k].name,
|
||||||
|
offset=vector(x_off,y_off))
|
||||||
|
|
||||||
|
|
||||||
def add_bank_select(self):
|
def create_bank_select(self):
|
||||||
""" Instantiate the bank select logic. """
|
""" Create the bank select logic. """
|
||||||
|
|
||||||
if not self.num_banks > 1:
|
if not self.num_banks > 1:
|
||||||
return
|
return
|
||||||
|
|
||||||
x_off = -(self.row_decoder.width + self.central_bus_width + self.wordline_driver.width)
|
self.bank_select_inst = []
|
||||||
if self.col_addr_size > 0:
|
for k in range(self.total_ports):
|
||||||
y_off = min(self.col_decoder_inst[0].by(), self.col_mux_array_inst[0].by())
|
self.bank_select_inst.append(self.add_inst(name="bank_select",
|
||||||
else:
|
mod=self.bank_select))
|
||||||
y_off = self.row_decoder_inst[0].by()
|
|
||||||
y_off -= (self.bank_select.height + drc["well_to_well"])
|
|
||||||
self.bank_select_pos = vector(x_off,y_off)
|
|
||||||
self.bank_select_inst = self.add_inst(name="bank_select",
|
|
||||||
mod=self.bank_select,
|
|
||||||
offset=self.bank_select_pos)
|
|
||||||
|
|
||||||
temp = []
|
temp = []
|
||||||
temp.extend(self.input_control_signals)
|
temp.extend(self.input_control_signals)
|
||||||
|
|
@ -463,23 +530,44 @@ class bank(design.design):
|
||||||
temp.extend(["vdd", "gnd"])
|
temp.extend(["vdd", "gnd"])
|
||||||
self.connect_inst(temp)
|
self.connect_inst(temp)
|
||||||
|
|
||||||
|
def place_bank_select(self):
|
||||||
|
""" Place the bank select logic. """
|
||||||
|
|
||||||
|
if not self.num_banks > 1:
|
||||||
|
return
|
||||||
|
|
||||||
|
# FIXME: place for multiport
|
||||||
|
for k in range(self.total_ports):
|
||||||
|
x_off = -(self.row_decoder.width + self.central_bus_width + self.wordline_driver.width)
|
||||||
|
if self.col_addr_size > 0:
|
||||||
|
y_off = min(self.col_decoder_inst[0].by(), self.col_mux_array_inst[0].by())
|
||||||
|
else:
|
||||||
|
y_off = self.row_decoder_inst[0].by()
|
||||||
|
y_off -= (self.bank_select.height + drc["well_to_well"])
|
||||||
|
self.bank_select_pos = vector(x_off,y_off)
|
||||||
|
self.place_inst(name=self.bank_select_inst[k].name,
|
||||||
|
offset=self.bank_select_pos)
|
||||||
|
|
||||||
|
|
||||||
def route_vdd_gnd(self):
|
def route_vdd_gnd(self):
|
||||||
""" Propagate all vdd/gnd pins up to this level for all modules """
|
""" Propagate all vdd/gnd pins up to this level for all modules """
|
||||||
|
|
||||||
# These are the instances that every bank has
|
# These are the instances that every bank has
|
||||||
top_instances = [self.bitcell_array_inst,
|
top_instances = [self.bitcell_array_inst]
|
||||||
self.precharge_array_inst[0],
|
|
||||||
self.sense_amp_array_inst[0],
|
for k in range(self.total_ports):
|
||||||
self.write_driver_array_inst[0],
|
top_instances.extend([self.precharge_array_inst[k],
|
||||||
self.row_decoder_inst[0],
|
self.sense_amp_array_inst[k],
|
||||||
self.wordline_driver_inst[0]]
|
self.write_driver_array_inst[k],
|
||||||
|
self.row_decoder_inst[k],
|
||||||
|
self.wordline_driver_inst[k]])
|
||||||
# Add these if we use the part...
|
# Add these if we use the part...
|
||||||
if self.col_addr_size > 0:
|
if self.col_addr_size > 0:
|
||||||
top_instances.append(self.col_decoder_inst[0])
|
top_instances.append(self.col_decoder_inst[k])
|
||||||
top_instances.append(self.col_mux_array_inst[0])
|
top_instances.append(self.col_mux_array_inst[k])
|
||||||
|
|
||||||
if self.num_banks > 1:
|
if self.num_banks > 1:
|
||||||
top_instances.append(self.bank_select_inst)
|
top_instances.append(self.bank_select_inst[k])
|
||||||
|
|
||||||
|
|
||||||
for inst in top_instances:
|
for inst in top_instances:
|
||||||
|
|
@ -497,7 +585,7 @@ class bank(design.design):
|
||||||
|
|
||||||
for gated_name in self.control_signals:
|
for gated_name in self.control_signals:
|
||||||
# Connect the inverter output to the central bus
|
# Connect the inverter output to the central bus
|
||||||
out_pos = self.bank_select_inst.get_pin(gated_name).rc()
|
out_pos = self.bank_select_inst[0].get_pin(gated_name).rc()
|
||||||
bus_pos = vector(self.bus_xoffset[gated_name].x, out_pos.y)
|
bus_pos = vector(self.bus_xoffset[gated_name].x, out_pos.y)
|
||||||
self.add_path("metal3",[out_pos, bus_pos])
|
self.add_path("metal3",[out_pos, bus_pos])
|
||||||
self.add_via_center(layers=("metal2", "via2", "metal3"),
|
self.add_via_center(layers=("metal2", "via2", "metal3"),
|
||||||
|
|
@ -511,9 +599,11 @@ class bank(design.design):
|
||||||
rotate=90)
|
rotate=90)
|
||||||
|
|
||||||
|
|
||||||
def setup_layout_constraints(self):
|
def setup_routing_constraints(self):
|
||||||
""" After the modules are instantiated, find the dimensions for the
|
"""
|
||||||
control bus, power ring, etc. """
|
After the modules are instantiated, find the dimensions for the
|
||||||
|
control bus, power ring, etc.
|
||||||
|
"""
|
||||||
|
|
||||||
#The minimum point is either the bottom of the address flops,
|
#The minimum point is either the bottom of the address flops,
|
||||||
#the column decoder (if there is one).
|
#the column decoder (if there is one).
|
||||||
|
|
@ -535,6 +625,7 @@ class bank(design.design):
|
||||||
|
|
||||||
# The max point is always the top of the precharge bitlines
|
# The max point is always the top of the precharge bitlines
|
||||||
# Add a vdd and gnd power rail above the array
|
# Add a vdd and gnd power rail above the array
|
||||||
|
# FIXME: Update multiport
|
||||||
self.max_y_offset = self.precharge_array_inst[0].uy() + 3*self.m1_width
|
self.max_y_offset = self.precharge_array_inst[0].uy() + 3*self.m1_width
|
||||||
self.max_x_offset = self.bitcell_array_inst.ur().x + 3*self.m1_width
|
self.max_x_offset = self.bitcell_array_inst.ur().x + 3*self.m1_width
|
||||||
self.min_x_offset = self.row_decoder_inst[0].lx()
|
self.min_x_offset = self.row_decoder_inst[0].lx()
|
||||||
|
|
@ -571,6 +662,7 @@ class bank(design.design):
|
||||||
def route_precharge_to_bitcell_array(self):
|
def route_precharge_to_bitcell_array(self):
|
||||||
""" Routing of BL and BR between pre-charge and bitcell array """
|
""" Routing of BL and BR between pre-charge and bitcell array """
|
||||||
|
|
||||||
|
# FIXME: Update for multiport
|
||||||
for k in range(self.total_read):
|
for k in range(self.total_read):
|
||||||
for i in range(self.num_cols):
|
for i in range(self.num_cols):
|
||||||
precharge_bl = self.precharge_array_inst[k].get_pin("bl[{}]".format(i)).bc()
|
precharge_bl = self.precharge_array_inst[k].get_pin("bl[{}]".format(i)).bc()
|
||||||
|
|
@ -592,6 +684,7 @@ class bank(design.design):
|
||||||
if self.col_addr_size==0:
|
if self.col_addr_size==0:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# FIXME: Update for multiport
|
||||||
for k in range(self.total_ports):
|
for k in range(self.total_ports):
|
||||||
for i in range(self.num_cols):
|
for i in range(self.num_cols):
|
||||||
col_mux_bl = self.col_mux_array_inst[k].get_pin("bl[{}]".format(i)).uc()
|
col_mux_bl = self.col_mux_array_inst[k].get_pin("bl[{}]".format(i)).uc()
|
||||||
|
|
@ -665,19 +758,17 @@ class bank(design.design):
|
||||||
def route_wordline_driver(self):
|
def route_wordline_driver(self):
|
||||||
""" Connecting Wordline driver output to Bitcell WL connection """
|
""" Connecting Wordline driver output to Bitcell WL connection """
|
||||||
|
|
||||||
for k in range(self.total_read):
|
|
||||||
# we don't care about bends after connecting to the input pin, so let the path code decide.
|
|
||||||
for i in range(self.num_rows):
|
for i in range(self.num_rows):
|
||||||
# The pre/post is to access the pin from "outside" the cell to avoid DRCs
|
# The pre/post is to access the pin from "outside" the cell to avoid DRCs
|
||||||
decoder_out_pos = self.row_decoder_inst[k].get_pin("decode[{}]".format(i)).rc()
|
decoder_out_pos = self.row_decoder_inst[0].get_pin("decode[{}]".format(i)).rc()
|
||||||
driver_in_pos = self.wordline_driver_inst[k].get_pin("in[{}]".format(i)).lc()
|
driver_in_pos = self.wordline_driver_inst[0].get_pin("in[{}]".format(i)).lc()
|
||||||
mid1 = decoder_out_pos.scale(0.5,1)+driver_in_pos.scale(0.5,0)
|
mid1 = decoder_out_pos.scale(0.5,1)+driver_in_pos.scale(0.5,0)
|
||||||
mid2 = decoder_out_pos.scale(0.5,0)+driver_in_pos.scale(0.5,1)
|
mid2 = decoder_out_pos.scale(0.5,0)+driver_in_pos.scale(0.5,1)
|
||||||
self.add_path("metal1", [decoder_out_pos, mid1, mid2, driver_in_pos])
|
self.add_path("metal1", [decoder_out_pos, mid1, mid2, driver_in_pos])
|
||||||
|
|
||||||
# The mid guarantees we exit the input cell to the right.
|
# The mid guarantees we exit the input cell to the right.
|
||||||
driver_wl_pos = self.wordline_driver_inst[k].get_pin("wl[{}]".format(i)).rc()
|
driver_wl_pos = self.wordline_driver_inst[0].get_pin("wl[{}]".format(i)).rc()
|
||||||
bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.total_wl_list[k]+"[{}]".format(i)).lc()
|
bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.total_wl_list[0]+"[{}]".format(i)).lc()
|
||||||
mid1 = driver_wl_pos.scale(0.5,1)+bitcell_wl_pos.scale(0.5,0)
|
mid1 = driver_wl_pos.scale(0.5,1)+bitcell_wl_pos.scale(0.5,0)
|
||||||
mid2 = driver_wl_pos.scale(0.5,0)+bitcell_wl_pos.scale(0.5,1)
|
mid2 = driver_wl_pos.scale(0.5,0)+bitcell_wl_pos.scale(0.5,1)
|
||||||
self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
|
self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos])
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,8 @@ class hierarchical_decoder(design.design):
|
||||||
self.route_input_rails()
|
self.route_input_rails()
|
||||||
self.route_predecode_rails()
|
self.route_predecode_rails()
|
||||||
self.route_vdd_gnd()
|
self.route_vdd_gnd()
|
||||||
|
self.offset_all_coordinates()
|
||||||
|
self.DRC_LVS()
|
||||||
|
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
self.inv = pinv()
|
self.inv = pinv()
|
||||||
|
|
|
||||||
|
|
@ -37,17 +37,17 @@ class hierarchical_predecode(design.design):
|
||||||
self.inv = pinv()
|
self.inv = pinv()
|
||||||
self.add_mod(self.inv)
|
self.add_mod(self.inv)
|
||||||
|
|
||||||
self.create_nand(self.number_of_inputs)
|
self.add_nand(self.number_of_inputs)
|
||||||
self.add_mod(self.nand)
|
self.add_mod(self.nand)
|
||||||
|
|
||||||
def create_nand(self,inputs):
|
def add_nand(self,inputs):
|
||||||
""" Create the NAND for the predecode input stage """
|
""" Create the NAND for the predecode input stage """
|
||||||
if inputs==2:
|
if inputs==2:
|
||||||
self.nand = pnand2()
|
self.nand = pnand2()
|
||||||
elif inputs==3:
|
elif inputs==3:
|
||||||
self.nand = pnand3()
|
self.nand = pnand3()
|
||||||
else:
|
else:
|
||||||
debug.error("Invalid number of predecode inputs.",-1)
|
debug.error("Invalid number of predecode inputs: {}".format(inputs),-1)
|
||||||
|
|
||||||
def setup_constraints(self):
|
def setup_constraints(self):
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ class hierarchical_predecode3x8(hierarchical_predecode):
|
||||||
["in[0]", "inbar[1]", "in[2]", "Z[5]", "vdd", "gnd"],
|
["in[0]", "inbar[1]", "in[2]", "Z[5]", "vdd", "gnd"],
|
||||||
["inbar[0]", "in[1]", "in[2]", "Z[6]", "vdd", "gnd"],
|
["inbar[0]", "in[1]", "in[2]", "Z[6]", "vdd", "gnd"],
|
||||||
["in[0]", "in[1]", "in[2]", "Z[7]", "vdd", "gnd"]]
|
["in[0]", "in[1]", "in[2]", "Z[7]", "vdd", "gnd"]]
|
||||||
self.create_nand(connections)
|
self.create_nand_array(connections)
|
||||||
|
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -41,7 +41,7 @@ class hierarchical_predecode3x8(hierarchical_predecode):
|
||||||
self.route_rails()
|
self.route_rails()
|
||||||
self.place_input_inverters()
|
self.place_input_inverters()
|
||||||
self.place_output_inverters()
|
self.place_output_inverters()
|
||||||
self.place_nand()
|
self.place_nand_array()
|
||||||
self.route()
|
self.route()
|
||||||
self.DRC_LVS()
|
self.DRC_LVS()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,9 +28,8 @@ class pbitcell(pgate.pgate):
|
||||||
self.num_write = num_write
|
self.num_write = num_write
|
||||||
self.num_read = num_read
|
self.num_read = num_read
|
||||||
|
|
||||||
self.add_pins()
|
self.create_netlist()
|
||||||
self.create_layout()
|
self.create_layout()
|
||||||
self.DRC_LVS()
|
|
||||||
|
|
||||||
pbitcell.width = self.width
|
pbitcell.width = self.width
|
||||||
pbitcell.height = self.height
|
pbitcell.height = self.height
|
||||||
|
|
@ -61,6 +60,9 @@ class pbitcell(pgate.pgate):
|
||||||
self.add_pin("gnd")
|
self.add_pin("gnd")
|
||||||
|
|
||||||
|
|
||||||
|
def create_netlist(self):
|
||||||
|
self.add_pins()
|
||||||
|
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
self.create_ptx()
|
self.create_ptx()
|
||||||
self.calculate_spacing()
|
self.calculate_spacing()
|
||||||
|
|
@ -75,6 +77,7 @@ class pbitcell(pgate.pgate):
|
||||||
self.add_read_ports()
|
self.add_read_ports()
|
||||||
self.extend_well()
|
self.extend_well()
|
||||||
self.offset_all_coordinates()
|
self.offset_all_coordinates()
|
||||||
|
self.DRC_LVS()
|
||||||
|
|
||||||
|
|
||||||
def create_ptx(self):
|
def create_ptx(self):
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,8 @@ class pinv(pgate.pgate):
|
||||||
self.height = height # Maybe minimize height if not defined in future?
|
self.height = height # Maybe minimize height if not defined in future?
|
||||||
self.route_output = False
|
self.route_output = False
|
||||||
|
|
||||||
self.add_pins()
|
|
||||||
|
self.create_netlist()
|
||||||
self.create_layout()
|
self.create_layout()
|
||||||
|
|
||||||
# for run-time, we won't check every transitor DRC/LVS independently
|
# for run-time, we won't check every transitor DRC/LVS independently
|
||||||
|
|
@ -50,6 +51,10 @@ class pinv(pgate.pgate):
|
||||||
""" Adds pins for spice netlist """
|
""" Adds pins for spice netlist """
|
||||||
self.add_pin_list(["A", "Z", "vdd", "gnd"])
|
self.add_pin_list(["A", "Z", "vdd", "gnd"])
|
||||||
|
|
||||||
|
def create_netlist(self):
|
||||||
|
""" Calls all functions related to the generation of the netlist """
|
||||||
|
self.add_pins()
|
||||||
|
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
""" Calls all functions related to the generation of the layout """
|
""" Calls all functions related to the generation of the layout """
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,48 +19,44 @@ class pinvbuf(design.design):
|
||||||
|
|
||||||
def __init__(self, driver_size=4, height=bitcell.height, name=""):
|
def __init__(self, driver_size=4, height=bitcell.height, name=""):
|
||||||
|
|
||||||
stage_effort = 4
|
self.stage_effort = 4
|
||||||
|
self.row_height = height
|
||||||
# FIXME: Change the number of stages to support high drives.
|
# FIXME: Change the number of stages to support high drives.
|
||||||
|
|
||||||
# stage effort of 4 or less
|
# stage effort of 4 or less
|
||||||
# The pinvbuf has a FO of 2 for the first stage, so the second stage
|
# The pinvbuf has a FO of 2 for the first stage, so the second stage
|
||||||
# should be sized "half" to prevent loading of the first stage
|
# should be sized "half" to prevent loading of the first stage
|
||||||
predriver_size = max(int(driver_size/(stage_effort/2)),1)
|
self.driver_size = driver_size
|
||||||
|
self.predriver_size = max(int(self.driver_size/(self.stage_effort/2)),1)
|
||||||
if name=="":
|
if name=="":
|
||||||
name = "pinvbuf_{0}_{1}_{2}".format(predriver_size, driver_size, pinvbuf.unique_id)
|
name = "pinvbuf_{0}_{1}_{2}".format(self.predriver_size, self.driver_size, pinvbuf.unique_id)
|
||||||
pinvbuf.unique_id += 1
|
pinvbuf.unique_id += 1
|
||||||
|
|
||||||
design.design.__init__(self, name)
|
design.design.__init__(self, name)
|
||||||
debug.info(1, "Creating {}".format(self.name))
|
debug.info(1, "Creating {}".format(self.name))
|
||||||
|
|
||||||
|
self.create_netlist()
|
||||||
|
self.create_layout()
|
||||||
|
|
||||||
# Shield the cap, but have at least a stage effort of 4
|
|
||||||
input_size = max(1,int(predriver_size/stage_effort))
|
|
||||||
self.inv = pinv(size=input_size, height=height)
|
|
||||||
self.add_mod(self.inv)
|
|
||||||
|
|
||||||
self.inv1 = pinv(size=predriver_size, height=height)
|
def create_netlist(self):
|
||||||
self.add_mod(self.inv1)
|
self.add_pins()
|
||||||
|
self.add_modules()
|
||||||
|
self.create_insts()
|
||||||
|
|
||||||
self.inv2 = pinv(size=driver_size, height=height)
|
def create_layout(self):
|
||||||
self.add_mod(self.inv2)
|
|
||||||
|
|
||||||
self.width = 2*self.inv1.width + self.inv2.width
|
self.width = 2*self.inv1.width + self.inv2.width
|
||||||
self.height = 2*self.inv1.height
|
self.height = 2*self.inv1.height
|
||||||
|
|
||||||
self.create_layout()
|
self.place_insts()
|
||||||
|
self.route_wires()
|
||||||
|
self.add_layout_pins()
|
||||||
|
|
||||||
self.offset_all_coordinates()
|
self.offset_all_coordinates()
|
||||||
|
|
||||||
self.DRC_LVS()
|
self.DRC_LVS()
|
||||||
|
|
||||||
def create_layout(self):
|
|
||||||
self.add_pins()
|
|
||||||
self.add_insts()
|
|
||||||
self.add_wires()
|
|
||||||
self.add_layout_pins()
|
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
self.add_pin("A")
|
self.add_pin("A")
|
||||||
self.add_pin("Zb")
|
self.add_pin("Zb")
|
||||||
|
|
@ -68,35 +64,58 @@ class pinvbuf(design.design):
|
||||||
self.add_pin("vdd")
|
self.add_pin("vdd")
|
||||||
self.add_pin("gnd")
|
self.add_pin("gnd")
|
||||||
|
|
||||||
def add_insts(self):
|
def add_modules(self):
|
||||||
# Add INV1 to the right (capacitance shield)
|
|
||||||
|
# Shield the cap, but have at least a stage effort of 4
|
||||||
|
input_size = max(1,int(self.predriver_size/self.stage_effort))
|
||||||
|
self.inv = pinv(size=input_size, height=self.row_height)
|
||||||
|
self.add_mod(self.inv)
|
||||||
|
|
||||||
|
self.inv1 = pinv(size=self.predriver_size, height=self.row_height)
|
||||||
|
self.add_mod(self.inv1)
|
||||||
|
|
||||||
|
self.inv2 = pinv(size=self.driver_size, height=self.row_height)
|
||||||
|
self.add_mod(self.inv2)
|
||||||
|
|
||||||
|
def create_insts(self):
|
||||||
|
# Create INV1 (capacitance shield)
|
||||||
self.inv1_inst=self.add_inst(name="buf_inv1",
|
self.inv1_inst=self.add_inst(name="buf_inv1",
|
||||||
mod=self.inv,
|
mod=self.inv)
|
||||||
offset=vector(0,0))
|
|
||||||
self.connect_inst(["A", "zb_int", "vdd", "gnd"])
|
self.connect_inst(["A", "zb_int", "vdd", "gnd"])
|
||||||
|
|
||||||
|
|
||||||
# Add INV2 to the right
|
|
||||||
self.inv2_inst=self.add_inst(name="buf_inv2",
|
self.inv2_inst=self.add_inst(name="buf_inv2",
|
||||||
mod=self.inv1,
|
mod=self.inv1)
|
||||||
offset=vector(self.inv1_inst.rx(),0))
|
|
||||||
self.connect_inst(["zb_int", "z_int", "vdd", "gnd"])
|
self.connect_inst(["zb_int", "z_int", "vdd", "gnd"])
|
||||||
|
|
||||||
# Add INV3 to the right
|
|
||||||
self.inv3_inst=self.add_inst(name="buf_inv3",
|
self.inv3_inst=self.add_inst(name="buf_inv3",
|
||||||
mod=self.inv2,
|
mod=self.inv2)
|
||||||
offset=vector(self.inv2_inst.rx(),0))
|
|
||||||
self.connect_inst(["z_int", "Zb", "vdd", "gnd"])
|
self.connect_inst(["z_int", "Zb", "vdd", "gnd"])
|
||||||
|
|
||||||
# Add INV4 to the bottom
|
|
||||||
self.inv4_inst=self.add_inst(name="buf_inv4",
|
self.inv4_inst=self.add_inst(name="buf_inv4",
|
||||||
mod=self.inv2,
|
mod=self.inv2)
|
||||||
offset=vector(self.inv2_inst.rx(),2*self.inv2.height),
|
|
||||||
mirror = "MX")
|
|
||||||
self.connect_inst(["zb_int", "Z", "vdd", "gnd"])
|
self.connect_inst(["zb_int", "Z", "vdd", "gnd"])
|
||||||
|
|
||||||
|
def place_insts(self):
|
||||||
|
# Add INV1 to the right (capacitance shield)
|
||||||
|
self.place_inst(name="buf_inv1",
|
||||||
|
offset=vector(0,0))
|
||||||
|
|
||||||
def add_wires(self):
|
# Add INV2 to the right
|
||||||
|
self.place_inst(name="buf_inv2",
|
||||||
|
offset=vector(self.inv1_inst.rx(),0))
|
||||||
|
|
||||||
|
# Add INV3 to the right
|
||||||
|
self.place_inst(name="buf_inv3",
|
||||||
|
offset=vector(self.inv2_inst.rx(),0))
|
||||||
|
|
||||||
|
# Add INV4 to the bottom
|
||||||
|
self.place_inst(name="buf_inv4",
|
||||||
|
offset=vector(self.inv2_inst.rx(),2*self.inv2.height),
|
||||||
|
mirror = "MX")
|
||||||
|
|
||||||
|
|
||||||
|
def route_wires(self):
|
||||||
# inv1 Z to inv2 A
|
# inv1 Z to inv2 A
|
||||||
z1_pin = self.inv1_inst.get_pin("Z")
|
z1_pin = self.inv1_inst.get_pin("Z")
|
||||||
a2_pin = self.inv2_inst.get_pin("A")
|
a2_pin = self.inv2_inst.get_pin("A")
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ class pnand2(pgate.pgate):
|
||||||
debug.check(size==1,"Size 1 pnand2 is only supported now.")
|
debug.check(size==1,"Size 1 pnand2 is only supported now.")
|
||||||
self.tx_mults = 1
|
self.tx_mults = 1
|
||||||
|
|
||||||
self.add_pins()
|
self.create_netlist()
|
||||||
self.create_layout()
|
self.create_layout()
|
||||||
#self.DRC_LVS()
|
#self.DRC_LVS()
|
||||||
|
|
||||||
|
|
@ -44,6 +44,10 @@ class pnand2(pgate.pgate):
|
||||||
""" Adds pins for spice netlist """
|
""" Adds pins for spice netlist """
|
||||||
self.add_pin_list(["A", "B", "Z", "vdd", "gnd"])
|
self.add_pin_list(["A", "B", "Z", "vdd", "gnd"])
|
||||||
|
|
||||||
|
|
||||||
|
def create_netlist(self):
|
||||||
|
self.add_pins()
|
||||||
|
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
""" Calls all functions related to the generation of the layout """
|
""" Calls all functions related to the generation of the layout """
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ class pnand3(pgate.pgate):
|
||||||
debug.check(size==1,"Size 1 pnand3 is only supported now.")
|
debug.check(size==1,"Size 1 pnand3 is only supported now.")
|
||||||
self.tx_mults = 1
|
self.tx_mults = 1
|
||||||
|
|
||||||
self.add_pins()
|
self.create_netlist()
|
||||||
self.create_layout()
|
self.create_layout()
|
||||||
#self.DRC_LVS()
|
#self.DRC_LVS()
|
||||||
|
|
||||||
|
|
@ -47,6 +47,9 @@ class pnand3(pgate.pgate):
|
||||||
""" Adds pins for spice netlist """
|
""" Adds pins for spice netlist """
|
||||||
self.add_pin_list(["A", "B", "C", "Z", "vdd", "gnd"])
|
self.add_pin_list(["A", "B", "C", "Z", "vdd", "gnd"])
|
||||||
|
|
||||||
|
def create_netlist(self):
|
||||||
|
self.add_pins()
|
||||||
|
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
""" Calls all functions related to the generation of the layout """
|
""" Calls all functions related to the generation of the layout """
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ class pnor2(pgate.pgate):
|
||||||
debug.check(size==1,"Size 1 pnor2 is only supported now.")
|
debug.check(size==1,"Size 1 pnor2 is only supported now.")
|
||||||
self.tx_mults = 1
|
self.tx_mults = 1
|
||||||
|
|
||||||
self.add_pins()
|
self.create_netlist()
|
||||||
self.create_layout()
|
self.create_layout()
|
||||||
#self.DRC_LVS()
|
#self.DRC_LVS()
|
||||||
|
|
||||||
|
|
@ -45,6 +45,9 @@ class pnor2(pgate.pgate):
|
||||||
""" Adds pins for spice netlist """
|
""" Adds pins for spice netlist """
|
||||||
self.add_pin_list(["A", "B", "Z", "vdd", "gnd"])
|
self.add_pin_list(["A", "B", "Z", "vdd", "gnd"])
|
||||||
|
|
||||||
|
def create_netlist(self):
|
||||||
|
self.add_pins()
|
||||||
|
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
""" Calls all functions related to the generation of the layout """
|
""" Calls all functions related to the generation of the layout """
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,13 +31,15 @@ class precharge(pgate.pgate):
|
||||||
self.bitcell_bl = bitcell_bl
|
self.bitcell_bl = bitcell_bl
|
||||||
self.bitcell_br = bitcell_br
|
self.bitcell_br = bitcell_br
|
||||||
|
|
||||||
self.add_pins()
|
self.create_netlist()
|
||||||
self.create_layout()
|
self.create_layout()
|
||||||
self.DRC_LVS()
|
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
self.add_pin_list(["bl", "br", "en", "vdd"])
|
self.add_pin_list(["bl", "br", "en", "vdd"])
|
||||||
|
|
||||||
|
def create_netlist(self):
|
||||||
|
self.add_pins()
|
||||||
|
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
self.create_ptx()
|
self.create_ptx()
|
||||||
self.add_ptx()
|
self.add_ptx()
|
||||||
|
|
@ -47,6 +49,7 @@ class precharge(pgate.pgate):
|
||||||
self.add_vdd_rail()
|
self.add_vdd_rail()
|
||||||
self.add_bitlines()
|
self.add_bitlines()
|
||||||
self.connect_to_bitlines()
|
self.connect_to_bitlines()
|
||||||
|
self.DRC_LVS()
|
||||||
|
|
||||||
def create_ptx(self):
|
def create_ptx(self):
|
||||||
"""Initializes the upper and lower pmos"""
|
"""Initializes the upper and lower pmos"""
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ class ptx(design.design):
|
||||||
self.connect_poly = connect_poly
|
self.connect_poly = connect_poly
|
||||||
self.num_contacts = num_contacts
|
self.num_contacts = num_contacts
|
||||||
|
|
||||||
self.create_spice()
|
self.create_netlist()
|
||||||
self.create_layout()
|
self.create_layout()
|
||||||
|
|
||||||
self.translate_all(self.active_offset)
|
self.translate_all(self.active_offset)
|
||||||
|
|
@ -57,7 +57,7 @@ class ptx(design.design):
|
||||||
self.add_poly()
|
self.add_poly()
|
||||||
self.add_active_contacts()
|
self.add_active_contacts()
|
||||||
|
|
||||||
def create_spice(self):
|
def create_netlist(self):
|
||||||
self.add_pin_list(["D", "G", "S", "B"])
|
self.add_pin_list(["D", "G", "S", "B"])
|
||||||
|
|
||||||
# self.spice.append("\n.SUBCKT {0} {1}".format(self.name,
|
# self.spice.append("\n.SUBCKT {0} {1}".format(self.name,
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,15 @@ class single_level_column_mux(design.design):
|
||||||
self.bitcell = self.mod_bitcell()
|
self.bitcell = self.mod_bitcell()
|
||||||
|
|
||||||
self.ptx_width = tx_size * drc["minwidth_tx"]
|
self.ptx_width = tx_size * drc["minwidth_tx"]
|
||||||
self.add_pin_list(["bl", "br", "bl_out", "br_out", "sel", "gnd"])
|
|
||||||
|
self.create_netlist()
|
||||||
self.create_layout()
|
self.create_layout()
|
||||||
|
|
||||||
def create_layout(self):
|
def create_netlist(self):
|
||||||
|
self.add_pin_list(["bl", "br", "bl_out", "br_out", "sel", "gnd"])
|
||||||
self.add_ptx()
|
self.add_ptx()
|
||||||
|
|
||||||
|
def create_layout(self):
|
||||||
self.pin_height = 2*self.m2_width
|
self.pin_height = 2*self.m2_width
|
||||||
self.width = self.bitcell.width
|
self.width = self.bitcell.width
|
||||||
self.height = self.nmos_upper.uy() + self.pin_height
|
self.height = self.nmos_upper.uy() + self.pin_height
|
||||||
|
|
|
||||||
|
|
@ -37,9 +37,7 @@ class sram():
|
||||||
else:
|
else:
|
||||||
debug.error("Invalid number of banks.",-1)
|
debug.error("Invalid number of banks.",-1)
|
||||||
|
|
||||||
self.s.compute_sizes()
|
self.s.create_netlist()
|
||||||
self.s.create_modules()
|
|
||||||
self.s.add_pins()
|
|
||||||
self.s.create_layout()
|
self.s.create_layout()
|
||||||
|
|
||||||
# Can remove the following, but it helps for debug!
|
# Can remove the following, but it helps for debug!
|
||||||
|
|
|
||||||
|
|
@ -20,14 +20,38 @@ class sram_1bank(sram_base):
|
||||||
def __init__(self, word_size, num_words, name):
|
def __init__(self, word_size, num_words, name):
|
||||||
sram_base.__init__(self, word_size, num_words, 1, name)
|
sram_base.__init__(self, word_size, num_words, 1, name)
|
||||||
|
|
||||||
def add_modules(self):
|
def create_netlist(self):
|
||||||
|
self.compute_sizes()
|
||||||
|
self.add_modules()
|
||||||
|
# Must run this after add modules to get control pin names
|
||||||
|
self.add_pins()
|
||||||
|
self.create_modules()
|
||||||
|
|
||||||
|
def create_modules(self):
|
||||||
"""
|
"""
|
||||||
This adds the moduels for a single bank SRAM with control
|
This adds the modules for a single bank SRAM with control
|
||||||
|
logic.
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.bank_inst = self.create_bank()
|
||||||
|
|
||||||
|
self.control_logic_inst = self.create_control_logic()
|
||||||
|
|
||||||
|
self.row_addr_dff_inst = self.create_row_addr_dff()
|
||||||
|
|
||||||
|
if self.col_addr_dff:
|
||||||
|
self.col_addr_dff_inst = self.create_col_addr_dff()
|
||||||
|
|
||||||
|
self.data_dff_inst = self.create_data_dff()
|
||||||
|
|
||||||
|
def place_modules(self):
|
||||||
|
"""
|
||||||
|
This places the modules for a single bank SRAM with control
|
||||||
logic.
|
logic.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# No orientation or offset
|
# No orientation or offset
|
||||||
self.bank_inst = self.add_bank(0, [0, 0], 1, 1)
|
self.place_bank(self.bank_inst, [0, 0], 1, 1)
|
||||||
|
|
||||||
# The control logic is placed such that the vertical center (between the delay/RBL and
|
# The control logic is placed such that the vertical center (between the delay/RBL and
|
||||||
# the actual control logic is aligned with the vertical center of the bank (between
|
# the actual control logic is aligned with the vertical center of the bank (between
|
||||||
|
|
@ -36,12 +60,14 @@ class sram_1bank(sram_base):
|
||||||
# up to the row address DFFs.
|
# up to the row address DFFs.
|
||||||
control_pos = vector(-self.control_logic.width - 2*self.m2_pitch,
|
control_pos = vector(-self.control_logic.width - 2*self.m2_pitch,
|
||||||
self.bank.bank_center.y - self.control_logic.control_logic_center.y)
|
self.bank.bank_center.y - self.control_logic.control_logic_center.y)
|
||||||
self.add_control_logic(position=control_pos)
|
self.place_inst(name=self.control_logic_inst.name,
|
||||||
|
offset=control_pos)
|
||||||
|
|
||||||
# The row address bits are placed above the control logic aligned on the right.
|
# The row address bits are placed above the control logic aligned on the right.
|
||||||
row_addr_pos = vector(self.control_logic_inst.rx() - self.row_addr_dff.width,
|
row_addr_pos = vector(self.control_logic_inst.rx() - self.row_addr_dff.width,
|
||||||
self.control_logic_inst.uy())
|
self.control_logic_inst.uy())
|
||||||
self.add_row_addr_dff(row_addr_pos)
|
self.place_inst(name=self.row_addr_dff_inst.name,
|
||||||
|
offset=row_addr_pos)
|
||||||
|
|
||||||
# This is M2 pitch even though it is on M1 to help stem via spacings on the trunk
|
# This is M2 pitch even though it is on M1 to help stem via spacings on the trunk
|
||||||
data_gap = -self.m2_pitch*(self.word_size+1)
|
data_gap = -self.m2_pitch*(self.word_size+1)
|
||||||
|
|
@ -51,7 +77,8 @@ class sram_1bank(sram_base):
|
||||||
if self.col_addr_dff:
|
if self.col_addr_dff:
|
||||||
col_addr_pos = vector(self.bank.bank_center.x - self.col_addr_dff.width - self.bank.central_bus_width,
|
col_addr_pos = vector(self.bank.bank_center.x - self.col_addr_dff.width - self.bank.central_bus_width,
|
||||||
data_gap - self.col_addr_dff.height)
|
data_gap - self.col_addr_dff.height)
|
||||||
self.add_col_addr_dff(col_addr_pos)
|
self.place_inst(name=self.col_addr_dff_inst.name,
|
||||||
|
offset=col_addr_pos)
|
||||||
|
|
||||||
# Add the data flops below the bank to the right of the center of bank:
|
# Add the data flops below the bank to the right of the center of bank:
|
||||||
# This relies on the center point of the bank:
|
# This relies on the center point of the bank:
|
||||||
|
|
@ -60,7 +87,8 @@ class sram_1bank(sram_base):
|
||||||
# sense amps.
|
# sense amps.
|
||||||
data_pos = vector(self.bank.bank_center.x,
|
data_pos = vector(self.bank.bank_center.x,
|
||||||
data_gap - self.data_dff.height)
|
data_gap - self.data_dff.height)
|
||||||
self.add_data_dff(data_pos)
|
self.place_inst(self.data_dff.name,
|
||||||
|
offset=data_pos)
|
||||||
|
|
||||||
# two supply rails are already included in the bank, so just 2 here.
|
# two supply rails are already included in the bank, so just 2 here.
|
||||||
self.width = self.bank.width + self.control_logic.width + 2*self.supply_rail_pitch
|
self.width = self.bank.width + self.control_logic.width + 2*self.supply_rail_pitch
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,8 @@ class sram_base(design):
|
||||||
self.num_words = num_words
|
self.num_words = num_words
|
||||||
self.num_banks = num_banks
|
self.num_banks = num_banks
|
||||||
|
|
||||||
|
self.bank_insts = []
|
||||||
|
|
||||||
def compute_sizes(self):
|
def compute_sizes(self):
|
||||||
""" Computes the organization of the memory using bitcell size by trying to make it square."""
|
""" Computes the organization of the memory using bitcell size by trying to make it square."""
|
||||||
|
|
||||||
|
|
@ -114,9 +116,14 @@ class sram_base(design):
|
||||||
self.add_pin("gnd","GROUND")
|
self.add_pin("gnd","GROUND")
|
||||||
|
|
||||||
|
|
||||||
|
def create_netlist(self):
|
||||||
|
""" Netlist creation """
|
||||||
|
self.add_modules()
|
||||||
|
self.add_pins()
|
||||||
|
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
""" Layout creation """
|
""" Layout creation """
|
||||||
self.add_modules()
|
self.place_modules()
|
||||||
self.route()
|
self.route()
|
||||||
self.add_lvs_correspondence_points()
|
self.add_lvs_correspondence_points()
|
||||||
|
|
||||||
|
|
@ -235,7 +242,7 @@ class sram_base(design):
|
||||||
self.copy_layout_pin(inst, "gnd")
|
self.copy_layout_pin(inst, "gnd")
|
||||||
|
|
||||||
|
|
||||||
def create_multi_bank_modules(self):
|
def add_multi_bank_modules(self):
|
||||||
""" Create the multibank address flops and bank decoder """
|
""" Create the multibank address flops and bank decoder """
|
||||||
from dff_buf_array import dff_buf_array
|
from dff_buf_array import dff_buf_array
|
||||||
self.msb_address = dff_buf_array(name="msb_address",
|
self.msb_address = dff_buf_array(name="msb_address",
|
||||||
|
|
@ -247,7 +254,7 @@ class sram_base(design):
|
||||||
self.msb_decoder = self.bank.decoder.pre2_4
|
self.msb_decoder = self.bank.decoder.pre2_4
|
||||||
self.add_mod(self.msb_decoder)
|
self.add_mod(self.msb_decoder)
|
||||||
|
|
||||||
def create_modules(self):
|
def add_modules(self):
|
||||||
""" Create all the modules that will be used """
|
""" Create all the modules that will be used """
|
||||||
|
|
||||||
from control_logic import control_logic
|
from control_logic import control_logic
|
||||||
|
|
@ -280,7 +287,7 @@ class sram_base(design):
|
||||||
|
|
||||||
# Create bank decoder
|
# Create bank decoder
|
||||||
if(self.num_banks > 1):
|
if(self.num_banks > 1):
|
||||||
self.create_multi_bank_modules()
|
self.add_multi_bank_modules()
|
||||||
|
|
||||||
self.bank_count = 0
|
self.bank_count = 0
|
||||||
|
|
||||||
|
|
@ -289,7 +296,28 @@ class sram_base(design):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def add_bank(self, bank_num, position, x_flip, y_flip):
|
def create_bank(self):
|
||||||
|
""" Create a bank """
|
||||||
|
bank_num = len(self.bank_insts)
|
||||||
|
self.bank_insts.append(self.add_inst(name="bank{0}".format(bank_num),
|
||||||
|
mod=self.bank))
|
||||||
|
|
||||||
|
temp = []
|
||||||
|
for i in range(self.word_size):
|
||||||
|
temp.append("DOUT[{0}]".format(i))
|
||||||
|
for i in range(self.word_size):
|
||||||
|
temp.append("BANK_DIN[{0}]".format(i))
|
||||||
|
for i in range(self.bank_addr_size):
|
||||||
|
temp.append("A[{0}]".format(i))
|
||||||
|
if(self.num_banks > 1):
|
||||||
|
temp.append("bank_sel[{0}]".format(bank_num))
|
||||||
|
temp.extend(["s_en0", "w_en0", "clk_buf_bar","clk_buf" , "vdd", "gnd"])
|
||||||
|
self.connect_inst(temp)
|
||||||
|
|
||||||
|
return self.bank_insts[-1]
|
||||||
|
|
||||||
|
|
||||||
|
def place_bank(self, bank_inst, position, x_flip, y_flip):
|
||||||
""" Place a bank at the given position with orientations """
|
""" Place a bank at the given position with orientations """
|
||||||
|
|
||||||
# x_flip == 1 --> no flip in x_axis
|
# x_flip == 1 --> no flip in x_axis
|
||||||
|
|
@ -313,32 +341,19 @@ class sram_base(design):
|
||||||
else:
|
else:
|
||||||
bank_mirror = "R0"
|
bank_mirror = "R0"
|
||||||
|
|
||||||
bank_inst=self.add_inst(name="bank{0}".format(bank_num),
|
self.place_inst(name=bank_inst.name,
|
||||||
mod=self.bank,
|
|
||||||
offset=position,
|
offset=position,
|
||||||
mirror=bank_mirror,
|
mirror=bank_mirror,
|
||||||
rotate=bank_rotation)
|
rotate=bank_rotation)
|
||||||
|
|
||||||
temp = []
|
|
||||||
for i in range(self.word_size):
|
|
||||||
temp.append("DOUT[{0}]".format(i))
|
|
||||||
for i in range(self.word_size):
|
|
||||||
temp.append("BANK_DIN[{0}]".format(i))
|
|
||||||
for i in range(self.bank_addr_size):
|
|
||||||
temp.append("A[{0}]".format(i))
|
|
||||||
if(self.num_banks > 1):
|
|
||||||
temp.append("bank_sel[{0}]".format(bank_num))
|
|
||||||
temp.extend(["s_en0", "w_en0", "clk_buf_bar","clk_buf" , "vdd", "gnd"])
|
|
||||||
self.connect_inst(temp)
|
|
||||||
|
|
||||||
return bank_inst
|
return bank_inst
|
||||||
|
|
||||||
|
|
||||||
def add_row_addr_dff(self, position):
|
def create_row_addr_dff(self):
|
||||||
""" Add and place all address flops for the main decoder """
|
""" Add all address flops for the main decoder """
|
||||||
self.row_addr_dff_inst = self.add_inst(name="row_address",
|
inst = self.add_inst(name="row_address",
|
||||||
mod=self.row_addr_dff,
|
mod=self.row_addr_dff)
|
||||||
offset=position)
|
|
||||||
# inputs, outputs/output/bar
|
# inputs, outputs/output/bar
|
||||||
inputs = []
|
inputs = []
|
||||||
outputs = []
|
outputs = []
|
||||||
|
|
@ -347,13 +362,13 @@ class sram_base(design):
|
||||||
outputs.append("A[{}]".format(i+self.col_addr_size))
|
outputs.append("A[{}]".format(i+self.col_addr_size))
|
||||||
|
|
||||||
self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"])
|
self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"])
|
||||||
|
return inst
|
||||||
|
|
||||||
|
def create_col_addr_dff(self):
|
||||||
def add_col_addr_dff(self, position):
|
|
||||||
""" Add and place all address flops for the column decoder """
|
""" Add and place all address flops for the column decoder """
|
||||||
self.col_addr_dff_inst = self.add_inst(name="row_address",
|
inst = self.add_inst(name="col_address",
|
||||||
mod=self.col_addr_dff,
|
mod=self.col_addr_dff)
|
||||||
offset=position)
|
|
||||||
# inputs, outputs/output/bar
|
# inputs, outputs/output/bar
|
||||||
inputs = []
|
inputs = []
|
||||||
outputs = []
|
outputs = []
|
||||||
|
|
@ -362,12 +377,13 @@ class sram_base(design):
|
||||||
outputs.append("A[{}]".format(i))
|
outputs.append("A[{}]".format(i))
|
||||||
|
|
||||||
self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"])
|
self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"])
|
||||||
|
return inst
|
||||||
|
|
||||||
def add_data_dff(self, position):
|
def create_data_dff(self):
|
||||||
""" Add and place all data flops """
|
""" Add and place all data flops """
|
||||||
self.data_dff_inst = self.add_inst(name="data_dff",
|
inst = self.add_inst(name="data_dff",
|
||||||
mod=self.data_dff,
|
mod=self.data_dff)
|
||||||
offset=position)
|
|
||||||
# inputs, outputs/output/bar
|
# inputs, outputs/output/bar
|
||||||
inputs = []
|
inputs = []
|
||||||
outputs = []
|
outputs = []
|
||||||
|
|
@ -376,14 +392,15 @@ class sram_base(design):
|
||||||
outputs.append("BANK_DIN[{}]".format(i))
|
outputs.append("BANK_DIN[{}]".format(i))
|
||||||
|
|
||||||
self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"])
|
self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"])
|
||||||
|
return inst
|
||||||
|
|
||||||
def add_control_logic(self, position):
|
def create_control_logic(self):
|
||||||
""" Add and place control logic """
|
""" Add and place control logic """
|
||||||
self.control_logic_inst=self.add_inst(name="control",
|
inst = self.add_inst(name="control",
|
||||||
mod=self.control_logic,
|
mod=self.control_logic)
|
||||||
offset=position)
|
|
||||||
self.connect_inst(self.control_logic_inputs + self.control_logic_outputs + ["vdd", "gnd"])
|
|
||||||
|
|
||||||
|
self.connect_inst(self.control_logic_inputs + self.control_logic_outputs + ["vdd", "gnd"])
|
||||||
|
return inst
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue