mirror of https://github.com/VLSIDA/OpenRAM.git
Finished merge
This commit is contained in:
commit
f29631695c
|
|
@ -227,6 +227,9 @@ class layout():
|
||||||
You can optionally rename the pin to a new name.
|
You can optionally rename the pin to a new name.
|
||||||
"""
|
"""
|
||||||
pins=instance.get_pins(pin_name)
|
pins=instance.get_pins(pin_name)
|
||||||
|
|
||||||
|
debug.check(len(pins)>0,"Could not find pin {}".format(pin_name))
|
||||||
|
|
||||||
for pin in pins:
|
for pin in pins:
|
||||||
if new_name=="":
|
if new_name=="":
|
||||||
new_name = pin.name
|
new_name = pin.name
|
||||||
|
|
@ -238,9 +241,7 @@ class layout():
|
||||||
You can optionally rename the pin to a new name.
|
You can optionally rename the pin to a new name.
|
||||||
"""
|
"""
|
||||||
for pin_name in self.pin_map.keys():
|
for pin_name in self.pin_map.keys():
|
||||||
pins=instance.get_pins(pin_name)
|
self.copy_layout_pin(instance, pin_name, prefix+pin_name)
|
||||||
for pin in pins:
|
|
||||||
self.add_layout_pin(prefix+pin_name, pin.layer, pin.ll(), pin.width(), pin.height())
|
|
||||||
|
|
||||||
def add_layout_pin_segment_center(self, text, layer, start, end):
|
def add_layout_pin_segment_center(self, text, layer, start, end):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ def log(str):
|
||||||
|
|
||||||
# use a static list of strings to store messages until the global paths are set up
|
# use a static list of strings to store messages until the global paths are set up
|
||||||
log.setup_output = []
|
log.setup_output = []
|
||||||
log.create_file = 1
|
log.create_file = True
|
||||||
|
|
||||||
|
|
||||||
def info(lev, str):
|
def info(lev, str):
|
||||||
|
|
|
||||||
|
|
@ -110,8 +110,7 @@ class bank(design.design):
|
||||||
|
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
self.route_bitlines(port)
|
self.route_bitlines(port)
|
||||||
self.route_wordline_driver(port)
|
self.route_port_address(port)
|
||||||
self.route_row_decoder(port)
|
|
||||||
self.route_column_address_lines(port)
|
self.route_column_address_lines(port)
|
||||||
self.route_control_lines(port)
|
self.route_control_lines(port)
|
||||||
if self.num_banks > 1:
|
if self.num_banks > 1:
|
||||||
|
|
@ -134,8 +133,7 @@ class bank(design.design):
|
||||||
|
|
||||||
self.create_bitcell_array()
|
self.create_bitcell_array()
|
||||||
self.create_port_data()
|
self.create_port_data()
|
||||||
self.create_row_decoder()
|
self.create_port_address()
|
||||||
self.create_wordline_driver()
|
|
||||||
self.create_column_decoder()
|
self.create_column_decoder()
|
||||||
self.create_bank_select()
|
self.create_bank_select()
|
||||||
|
|
||||||
|
|
@ -145,8 +143,7 @@ class bank(design.design):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.port_data_offsets = [None]*len(self.all_ports)
|
self.port_data_offsets = [None]*len(self.all_ports)
|
||||||
self.wordline_driver_offsets = [None]*len(self.all_ports)
|
self.port_address_offsets = [None]*len(self.all_ports)
|
||||||
self.row_decoder_offsets = [None]*len(self.all_ports)
|
|
||||||
|
|
||||||
self.column_decoder_offsets = [None]*len(self.all_ports)
|
self.column_decoder_offsets = [None]*len(self.all_ports)
|
||||||
self.bank_select_offsets = [None]*len(self.all_ports)
|
self.bank_select_offsets = [None]*len(self.all_ports)
|
||||||
|
|
@ -183,16 +180,14 @@ class bank(design.design):
|
||||||
# UPPER LEFT QUADRANT
|
# UPPER LEFT QUADRANT
|
||||||
# To the left of the bitcell array
|
# To the left of the bitcell array
|
||||||
# The wordline driver is placed to the right of the main decoder width.
|
# The wordline driver is placed to the right of the main decoder width.
|
||||||
x_offset = self.m2_gap + self.wordline_driver.width
|
x_offset = self.m2_gap + self.port_address.width
|
||||||
self.wordline_driver_offsets[port] = vector(-x_offset,0)
|
self.port_address_offsets[port] = vector(-x_offset,0)
|
||||||
x_offset += self.row_decoder.width + self.m2_gap
|
|
||||||
self.row_decoder_offsets[port] = vector(-x_offset,0)
|
|
||||||
|
|
||||||
# LOWER LEFT QUADRANT
|
# LOWER LEFT QUADRANT
|
||||||
# Place the col decoder left aligned with wordline driver plus halfway under row decoder
|
# Place the col decoder left aligned with wordline driver plus halfway under row decoder
|
||||||
# Place the col decoder left aligned with row decoder (x_offset doesn't change)
|
# Place the col decoder left aligned with row decoder (x_offset doesn't change)
|
||||||
# Below the bitcell array with well spacing
|
# Below the bitcell array with well spacing
|
||||||
x_offset = self.central_bus_width[port] + self.wordline_driver.width
|
x_offset = self.central_bus_width[port] + self.port_address.wordline_driver.width
|
||||||
if self.col_addr_size > 0:
|
if self.col_addr_size > 0:
|
||||||
x_offset += self.column_decoder.width + self.col_addr_bus_width
|
x_offset += self.column_decoder.width + self.col_addr_bus_width
|
||||||
y_offset = self.m2_gap + self.column_decoder.height
|
y_offset = self.m2_gap + self.column_decoder.height
|
||||||
|
|
@ -205,7 +200,7 @@ class bank(design.design):
|
||||||
if self.col_addr_size > 0:
|
if self.col_addr_size > 0:
|
||||||
y_offset = min(self.column_decoder_offsets[port].y, self.port_data[port].column_mux_offset.y)
|
y_offset = min(self.column_decoder_offsets[port].y, self.port_data[port].column_mux_offset.y)
|
||||||
else:
|
else:
|
||||||
y_offset = self.row_decoder_offsets[port].y
|
y_offset = self.port_address_offsets[port].y
|
||||||
if self.num_banks > 1:
|
if self.num_banks > 1:
|
||||||
y_offset += self.bank_select.height + drc("well_to_well")
|
y_offset += self.bank_select.height + drc("well_to_well")
|
||||||
self.bank_select_offsets[port] = vector(-x_offset,-y_offset)
|
self.bank_select_offsets[port] = vector(-x_offset,-y_offset)
|
||||||
|
|
@ -227,15 +222,13 @@ class bank(design.design):
|
||||||
# LOWER RIGHT QUADRANT
|
# LOWER RIGHT QUADRANT
|
||||||
# To the left of the bitcell array
|
# To the left of the bitcell array
|
||||||
# The wordline driver is placed to the right of the main decoder width.
|
# The wordline driver is placed to the right of the main decoder width.
|
||||||
x_offset = self.bitcell_array_right + self.wordline_driver.width
|
x_offset = self.bitcell_array_right + self.port_address.width + self.m2_gap
|
||||||
self.wordline_driver_offsets[port] = vector(x_offset,0)
|
self.port_address_offsets[port] = vector(x_offset,0)
|
||||||
x_offset += self.row_decoder.width + self.m2_gap
|
|
||||||
self.row_decoder_offsets[port] = vector(x_offset,0)
|
|
||||||
|
|
||||||
# UPPER RIGHT QUADRANT
|
# UPPER RIGHT QUADRANT
|
||||||
# Place the col decoder right aligned with wordline driver plus halfway under row decoder
|
# Place the col decoder right aligned with wordline driver plus halfway under row decoder
|
||||||
# Above the bitcell array with a well spacing
|
# Above the bitcell array with a well spacing
|
||||||
x_offset = self.bitcell_array_right + self.central_bus_width[port] + self.wordline_driver.width
|
x_offset = self.bitcell_array_right + self.central_bus_width[port] + self.port_address.wordline_driver.width
|
||||||
if self.col_addr_size > 0:
|
if self.col_addr_size > 0:
|
||||||
x_offset += self.column_decoder.width + self.col_addr_bus_width
|
x_offset += self.column_decoder.width + self.col_addr_bus_width
|
||||||
y_offset = self.bitcell_array_top + self.m2_gap + self.column_decoder.height
|
y_offset = self.bitcell_array_top + self.m2_gap + self.column_decoder.height
|
||||||
|
|
@ -249,7 +242,7 @@ class bank(design.design):
|
||||||
y_offset = max(self.column_decoder_offsets[port].y + self.column_decoder.height,
|
y_offset = max(self.column_decoder_offsets[port].y + self.column_decoder.height,
|
||||||
self.port_data[port].column_mux_offset.y + self.port_data[port].column_mux_array.height)
|
self.port_data[port].column_mux_offset.y + self.port_data[port].column_mux_array.height)
|
||||||
else:
|
else:
|
||||||
y_offset = self.row_decoder_offsets[port].y
|
y_offset = self.port_address_offsets[port].y
|
||||||
self.bank_select_offsets[port] = vector(x_offset,y_offset)
|
self.bank_select_offsets[port] = vector(x_offset,y_offset)
|
||||||
|
|
||||||
def place_instances(self):
|
def place_instances(self):
|
||||||
|
|
@ -264,8 +257,7 @@ class bank(design.design):
|
||||||
self.place_port_data(self.port_data_offsets)
|
self.place_port_data(self.port_data_offsets)
|
||||||
|
|
||||||
# UPPER LEFT QUADRANT
|
# UPPER LEFT QUADRANT
|
||||||
self.place_row_decoder(self.row_decoder_offsets)
|
self.place_port_address(self.port_address_offsets)
|
||||||
self.place_wordline_driver(self.wordline_driver_offsets)
|
|
||||||
|
|
||||||
# LOWER LEFT QUADRANT
|
# LOWER LEFT QUADRANT
|
||||||
self.place_column_decoder(self.column_decoder_offsets)
|
self.place_column_decoder(self.column_decoder_offsets)
|
||||||
|
|
@ -352,17 +344,11 @@ class bank(design.design):
|
||||||
self.port_data.append(temp_pre)
|
self.port_data.append(temp_pre)
|
||||||
self.add_mod(self.port_data[port])
|
self.add_mod(self.port_data[port])
|
||||||
|
|
||||||
self.row_decoder = factory.create(module_type="decoder",
|
|
||||||
rows=self.num_rows)
|
|
||||||
self.add_mod(self.row_decoder)
|
|
||||||
|
|
||||||
self.wordline_driver = factory.create(module_type="wordline_driver",
|
self.port_address = factory.create(module_type="port_address",
|
||||||
rows=self.num_rows,
|
cols=self.num_cols,
|
||||||
cols=self.num_cols)
|
rows=self.num_rows)
|
||||||
self.add_mod(self.wordline_driver)
|
self.add_mod(self.port_address)
|
||||||
|
|
||||||
self.inv = factory.create(module_type="pinv")
|
|
||||||
self.add_mod(self.inv)
|
|
||||||
|
|
||||||
if(self.num_banks > 1):
|
if(self.num_banks > 1):
|
||||||
self.bank_select = factory.create(module_type="bank_select")
|
self.bank_select = factory.create(module_type="bank_select")
|
||||||
|
|
@ -436,24 +422,25 @@ class bank(design.design):
|
||||||
mirror = "MX"
|
mirror = "MX"
|
||||||
self.port_data_inst[port].place(offset=offsets[port], mirror=mirror)
|
self.port_data_inst[port].place(offset=offsets[port], mirror=mirror)
|
||||||
|
|
||||||
def create_row_decoder(self):
|
def create_port_address(self):
|
||||||
""" Create the hierarchical row decoder """
|
""" Create the hierarchical row decoder """
|
||||||
|
|
||||||
self.row_decoder_inst = [None]*len(self.all_ports)
|
self.port_address_inst = [None]*len(self.all_ports)
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
self.row_decoder_inst[port] = self.add_inst(name="row_decoder{}".format(port),
|
self.port_address_inst[port] = self.add_inst(name="port_address{}".format(port),
|
||||||
mod=self.row_decoder)
|
mod=self.port_address)
|
||||||
|
|
||||||
temp = []
|
temp = []
|
||||||
for bit in range(self.row_addr_size):
|
for bit in range(self.row_addr_size):
|
||||||
temp.append("addr{0}_{1}".format(port,bit+self.col_addr_size))
|
temp.append("addr{0}_{1}".format(port,bit+self.col_addr_size))
|
||||||
|
temp.append("wl_en{0}".format(port))
|
||||||
for row in range(self.num_rows):
|
for row in range(self.num_rows):
|
||||||
temp.append("dec_out{0}_{1}".format(port,row))
|
temp.append(self.wl_names[port]+"_{0}".format(row))
|
||||||
temp.extend(["vdd", "gnd"])
|
temp.extend(["vdd", "gnd"])
|
||||||
self.connect_inst(temp)
|
self.connect_inst(temp)
|
||||||
|
|
||||||
|
|
||||||
def place_row_decoder(self, offsets):
|
def place_port_address(self, offsets):
|
||||||
""" Place the hierarchical row decoder """
|
""" Place the hierarchical row decoder """
|
||||||
|
|
||||||
debug.check(len(offsets)>=len(self.all_ports), "Insufficient offsets to place row decoder array.")
|
debug.check(len(offsets)>=len(self.all_ports), "Insufficient offsets to place row decoder array.")
|
||||||
|
|
@ -469,39 +456,7 @@ class bank(design.design):
|
||||||
mirror = "MY"
|
mirror = "MY"
|
||||||
else:
|
else:
|
||||||
mirror = "R0"
|
mirror = "R0"
|
||||||
self.row_decoder_inst[port].place(offset=offsets[port], mirror=mirror)
|
self.port_address_inst[port].place(offset=offsets[port], mirror=mirror)
|
||||||
|
|
||||||
|
|
||||||
def create_wordline_driver(self):
|
|
||||||
""" Create the Wordline Driver """
|
|
||||||
|
|
||||||
self.wordline_driver_inst = [None]*len(self.all_ports)
|
|
||||||
for port in self.all_ports:
|
|
||||||
self.wordline_driver_inst[port] = self.add_inst(name="wordline_driver{}".format(port),
|
|
||||||
mod=self.wordline_driver)
|
|
||||||
|
|
||||||
temp = []
|
|
||||||
for row in range(self.num_rows):
|
|
||||||
temp.append("dec_out{0}_{1}".format(port,row))
|
|
||||||
for row in range(self.num_rows):
|
|
||||||
temp.append(self.wl_names[port]+"_{0}".format(row))
|
|
||||||
temp.append(self.prefix+"wl_en{0}".format(port))
|
|
||||||
temp.append("vdd")
|
|
||||||
temp.append("gnd")
|
|
||||||
self.connect_inst(temp)
|
|
||||||
|
|
||||||
|
|
||||||
def place_wordline_driver(self, offsets):
|
|
||||||
""" Place the Wordline Driver """
|
|
||||||
|
|
||||||
debug.check(len(offsets)>=len(self.all_ports), "Insufficient offsets to place wordline driver array.")
|
|
||||||
|
|
||||||
for port in self.all_ports:
|
|
||||||
if port%2 == 1:
|
|
||||||
mirror = "MY"
|
|
||||||
else:
|
|
||||||
mirror = "R0"
|
|
||||||
self.wordline_driver_inst[port].place(offset=offsets[port], mirror=mirror)
|
|
||||||
|
|
||||||
|
|
||||||
def create_column_decoder(self):
|
def create_column_decoder(self):
|
||||||
|
|
@ -705,7 +660,7 @@ class bank(design.design):
|
||||||
width=data_pin.width())
|
width=data_pin.width())
|
||||||
|
|
||||||
|
|
||||||
def route_row_decoder(self, port):
|
def route_port_address_in(self, port):
|
||||||
""" Routes the row decoder inputs and supplies """
|
""" Routes the row decoder inputs and supplies """
|
||||||
|
|
||||||
# Create inputs for the row address lines
|
# Create inputs for the row address lines
|
||||||
|
|
@ -713,7 +668,7 @@ class bank(design.design):
|
||||||
addr_idx = row + self.col_addr_size
|
addr_idx = row + self.col_addr_size
|
||||||
decoder_name = "addr_{}".format(row)
|
decoder_name = "addr_{}".format(row)
|
||||||
addr_name = "addr{0}_{1}".format(port,addr_idx)
|
addr_name = "addr{0}_{1}".format(port,addr_idx)
|
||||||
self.copy_layout_pin(self.row_decoder_inst[port], decoder_name, addr_name)
|
self.copy_layout_pin(self.port_address_inst[port], decoder_name, addr_name)
|
||||||
|
|
||||||
|
|
||||||
def route_port_data_in(self, port):
|
def route_port_data_in(self, port):
|
||||||
|
|
@ -782,47 +737,36 @@ class bank(design.design):
|
||||||
vector(top_br.x,yoffset), top_br])
|
vector(top_br.x,yoffset), top_br])
|
||||||
|
|
||||||
|
|
||||||
def route_wordline_driver(self, port):
|
def route_port_address(self, port):
|
||||||
""" Connect Wordline driver to bitcell array wordline """
|
""" Connect Wordline driver to bitcell array wordline """
|
||||||
if port%2:
|
|
||||||
self.route_wordline_driver_right(port)
|
|
||||||
else:
|
|
||||||
self.route_wordline_driver_left(port)
|
|
||||||
|
|
||||||
def route_wordline_driver_left(self, port):
|
self.route_port_address_in(port)
|
||||||
|
|
||||||
|
if port%2:
|
||||||
|
self.route_port_address_right(port)
|
||||||
|
else:
|
||||||
|
self.route_port_address_left(port)
|
||||||
|
|
||||||
|
def route_port_address_left(self, port):
|
||||||
""" Connecting Wordline driver output to Bitcell WL connection """
|
""" Connecting Wordline driver output to Bitcell WL connection """
|
||||||
|
|
||||||
for row in range(self.num_rows):
|
for row in range(self.num_rows):
|
||||||
# The pre/post is to access the pin from "outside" the cell to avoid DRCs
|
|
||||||
decoder_out_pos = self.row_decoder_inst[port].get_pin("decode_{}".format(row)).rc()
|
|
||||||
driver_in_pos = self.wordline_driver_inst[port].get_pin("in_{}".format(row)).lc()
|
|
||||||
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)
|
|
||||||
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[port].get_pin("wl_{}".format(row)).rc()
|
driver_wl_pos = self.port_address_inst[port].get_pin("wl_{}".format(row)).rc()
|
||||||
bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port]+"_{}".format(row)).lc()
|
bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port]+"_{}".format(row)).lc()
|
||||||
mid1 = driver_wl_pos.scale(0,1) + vector(0.5*self.wordline_driver_inst[port].rx() + 0.5*self.bitcell_array_inst.lx(),0)
|
mid1 = driver_wl_pos.scale(0,1) + vector(0.5*self.port_address_inst[port].rx() + 0.5*self.bitcell_array_inst.lx(),0)
|
||||||
mid2 = mid1.scale(1,0)+bitcell_wl_pos.scale(0.5,1)
|
mid2 = mid1.scale(1,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])
|
||||||
|
|
||||||
|
|
||||||
def route_wordline_driver_right(self, port):
|
def route_port_address_right(self, port):
|
||||||
""" Connecting Wordline driver output to Bitcell WL connection """
|
""" Connecting Wordline driver output to Bitcell WL connection """
|
||||||
|
|
||||||
for row in range(self.num_rows):
|
for row in range(self.num_rows):
|
||||||
# The pre/post is to access the pin from "outside" the cell to avoid DRCs
|
|
||||||
decoder_out_pos = self.row_decoder_inst[port].get_pin("decode_{}".format(row)).lc()
|
|
||||||
driver_in_pos = self.wordline_driver_inst[port].get_pin("in_{}".format(row)).rc()
|
|
||||||
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)
|
|
||||||
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[port].get_pin("wl_{}".format(row)).lc()
|
driver_wl_pos = self.port_address_inst[port].get_pin("wl_{}".format(row)).lc()
|
||||||
bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port]+"_{}".format(row)).rc()
|
bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.wl_names[port]+"_{}".format(row)).rc()
|
||||||
mid1 = driver_wl_pos.scale(0,1) + vector(0.5*self.wordline_driver_inst[port].lx() + 0.5*self.bitcell_array_inst.rx(),0)
|
mid1 = driver_wl_pos.scale(0,1) + vector(0.5*self.port_address_inst[port].lx() + 0.5*self.bitcell_array_inst.rx(),0)
|
||||||
mid2 = mid1.scale(1,0)+bitcell_wl_pos.scale(0,1)
|
mid2 = mid1.scale(1,0)+bitcell_wl_pos.scale(0,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])
|
||||||
|
|
||||||
|
|
@ -937,10 +881,10 @@ class bank(design.design):
|
||||||
# clk to wordline_driver
|
# clk to wordline_driver
|
||||||
control_signal = self.prefix+"wl_en{}".format(port)
|
control_signal = self.prefix+"wl_en{}".format(port)
|
||||||
if port%2:
|
if port%2:
|
||||||
pin_pos = self.wordline_driver_inst[port].get_pin("en_bar").uc()
|
pin_pos = self.port_address_inst[port].get_pin("wl_en").uc()
|
||||||
mid_pos = pin_pos + vector(0,self.m2_gap) # to route down to the top of the bus
|
mid_pos = pin_pos + vector(0,self.m2_gap) # to route down to the top of the bus
|
||||||
else:
|
else:
|
||||||
pin_pos = self.wordline_driver_inst[port].get_pin("en_bar").bc()
|
pin_pos = self.port_address_inst[port].get_pin("wl_en").bc()
|
||||||
mid_pos = pin_pos - vector(0,self.m2_gap) # to route down to the top of the bus
|
mid_pos = pin_pos - vector(0,self.m2_gap) # to route down to the top of the bus
|
||||||
control_x_offset = self.bus_xoffset[port][control_signal].x
|
control_x_offset = self.bus_xoffset[port][control_signal].x
|
||||||
control_pos = vector(control_x_offset, mid_pos.y)
|
control_pos = vector(control_x_offset, mid_pos.y)
|
||||||
|
|
@ -986,14 +930,14 @@ class bank(design.design):
|
||||||
#Decoder is assumed to have settled before the negative edge of the clock. Delay model relies on this assumption
|
#Decoder is assumed to have settled before the negative edge of the clock. Delay model relies on this assumption
|
||||||
stage_effort_list = []
|
stage_effort_list = []
|
||||||
wordline_cout = self.bitcell_array.get_wordline_cin() + external_cout
|
wordline_cout = self.bitcell_array.get_wordline_cin() + external_cout
|
||||||
stage_effort_list += self.wordline_driver.determine_wordline_stage_efforts(wordline_cout,inp_is_rise)
|
stage_effort_list += self.port_address.wordline_driver.determine_wordline_stage_efforts(wordline_cout,inp_is_rise)
|
||||||
|
|
||||||
return stage_effort_list
|
return stage_effort_list
|
||||||
|
|
||||||
def get_wl_en_cin(self):
|
def get_wl_en_cin(self):
|
||||||
"""Get the relative capacitance of all the clk connections in the bank"""
|
"""Get the relative capacitance of all the clk connections in the bank"""
|
||||||
#wl_en only used in the wordline driver.
|
#wl_en only used in the wordline driver.
|
||||||
return self.wordline_driver.get_wl_en_cin()
|
return self.port_address.wordline_driver.get_wl_en_cin()
|
||||||
|
|
||||||
def get_w_en_cin(self):
|
def get_w_en_cin(self):
|
||||||
"""Get the relative capacitance of all the clk connections in the bank"""
|
"""Get the relative capacitance of all the clk connections in the bank"""
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,163 @@
|
||||||
|
# See LICENSE for licensing information.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016-2019 Regents of the University of California
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
import sys
|
||||||
|
from tech import drc, parameter
|
||||||
|
from math import log
|
||||||
|
import debug
|
||||||
|
import design
|
||||||
|
from sram_factory import factory
|
||||||
|
from vector import vector
|
||||||
|
|
||||||
|
from globals import OPTS
|
||||||
|
|
||||||
|
class port_address(design.design):
|
||||||
|
"""
|
||||||
|
Create the address port (row decoder and wordline driver)..
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, cols, rows, name=""):
|
||||||
|
|
||||||
|
self.num_cols = cols
|
||||||
|
self.num_rows = rows
|
||||||
|
self.addr_size = int(log(self.num_rows, 2))
|
||||||
|
|
||||||
|
if name == "":
|
||||||
|
name = "port_address_{0}_{1}".format(cols,rows)
|
||||||
|
design.design.__init__(self, name)
|
||||||
|
debug.info(2, "create data port of cols {0} rows {1}".format(cols,rows))
|
||||||
|
|
||||||
|
self.create_netlist()
|
||||||
|
if not OPTS.netlist_only:
|
||||||
|
debug.check(len(self.all_ports)<=2,"Bank layout cannot handle more than two ports.")
|
||||||
|
self.create_layout()
|
||||||
|
self.add_boundary()
|
||||||
|
|
||||||
|
|
||||||
|
def create_netlist(self):
|
||||||
|
self.add_pins()
|
||||||
|
self.add_modules()
|
||||||
|
self.create_row_decoder()
|
||||||
|
self.create_wordline_driver()
|
||||||
|
|
||||||
|
def create_layout(self):
|
||||||
|
self.place_instances()
|
||||||
|
self.route_layout()
|
||||||
|
self.DRC_LVS()
|
||||||
|
|
||||||
|
def add_pins(self):
|
||||||
|
""" Adding pins for port address module"""
|
||||||
|
|
||||||
|
for bit in range(self.addr_size):
|
||||||
|
self.add_pin("addr_{0}".format(bit),"INPUT")
|
||||||
|
|
||||||
|
self.add_pin("wl_en", "INPUT")
|
||||||
|
|
||||||
|
for bit in range(self.num_rows):
|
||||||
|
self.add_pin("wl_{0}".format(bit),"OUTPUT")
|
||||||
|
|
||||||
|
self.add_pin("vdd","POWER")
|
||||||
|
self.add_pin("gnd","GROUND")
|
||||||
|
|
||||||
|
|
||||||
|
def route_layout(self):
|
||||||
|
""" Create routing amoung the modules """
|
||||||
|
self.route_pins()
|
||||||
|
self.route_internal()
|
||||||
|
self.route_supplies()
|
||||||
|
|
||||||
|
def route_supplies(self):
|
||||||
|
""" Propagate all vdd/gnd pins up to this level for all modules """
|
||||||
|
for inst in self.insts:
|
||||||
|
self.copy_power_pins(inst,"vdd")
|
||||||
|
self.copy_power_pins(inst,"gnd")
|
||||||
|
|
||||||
|
def route_pins(self):
|
||||||
|
for row in range(self.addr_size):
|
||||||
|
decoder_name = "addr_{}".format(row)
|
||||||
|
self.copy_layout_pin(self.row_decoder_inst, decoder_name)
|
||||||
|
|
||||||
|
for row in range(self.num_rows):
|
||||||
|
driver_name = "wl_{}".format(row)
|
||||||
|
self.copy_layout_pin(self.wordline_driver_inst, driver_name)
|
||||||
|
|
||||||
|
# FIXME: Is this still inverted!?
|
||||||
|
self.copy_layout_pin(self.wordline_driver_inst, "en_bar", "wl_en")
|
||||||
|
|
||||||
|
def route_internal(self):
|
||||||
|
for row in range(self.num_rows):
|
||||||
|
# The pre/post is to access the pin from "outside" the cell to avoid DRCs
|
||||||
|
decoder_out_pos = self.row_decoder_inst.get_pin("decode_{}".format(row)).rc()
|
||||||
|
driver_in_pos = self.wordline_driver_inst.get_pin("in_{}".format(row)).lc()
|
||||||
|
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)
|
||||||
|
self.add_path("metal1", [decoder_out_pos, mid1, mid2, driver_in_pos])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def add_modules(self):
|
||||||
|
|
||||||
|
self.row_decoder = factory.create(module_type="decoder",
|
||||||
|
rows=self.num_rows)
|
||||||
|
self.add_mod(self.row_decoder)
|
||||||
|
|
||||||
|
self.wordline_driver = factory.create(module_type="wordline_driver",
|
||||||
|
rows=self.num_rows,
|
||||||
|
cols=self.num_cols)
|
||||||
|
self.add_mod(self.wordline_driver)
|
||||||
|
|
||||||
|
|
||||||
|
def create_row_decoder(self):
|
||||||
|
""" Create the hierarchical row decoder """
|
||||||
|
|
||||||
|
self.row_decoder_inst = self.add_inst(name="row_decoder",
|
||||||
|
mod=self.row_decoder)
|
||||||
|
|
||||||
|
temp = []
|
||||||
|
for bit in range(self.addr_size):
|
||||||
|
temp.append("addr_{0}".format(bit))
|
||||||
|
for row in range(self.num_rows):
|
||||||
|
temp.append("dec_out_{0}".format(row))
|
||||||
|
temp.extend(["vdd", "gnd"])
|
||||||
|
self.connect_inst(temp)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def create_wordline_driver(self):
|
||||||
|
""" Create the Wordline Driver """
|
||||||
|
|
||||||
|
self.wordline_driver_inst = self.add_inst(name="wordline_driver",
|
||||||
|
mod=self.wordline_driver)
|
||||||
|
|
||||||
|
temp = []
|
||||||
|
for row in range(self.num_rows):
|
||||||
|
temp.append("dec_out_{0}".format(row))
|
||||||
|
for row in range(self.num_rows):
|
||||||
|
temp.append("wl_{0}".format(row))
|
||||||
|
temp.append("wl_en")
|
||||||
|
temp.append("vdd")
|
||||||
|
temp.append("gnd")
|
||||||
|
self.connect_inst(temp)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def place_instances(self):
|
||||||
|
"""
|
||||||
|
Compute the offsets and place the instances.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# A space for wells or jogging m2
|
||||||
|
self.m2_gap = max(2*drc("pwell_to_nwell") + drc("well_enclosure_active"),
|
||||||
|
3*self.m2_pitch)
|
||||||
|
|
||||||
|
row_decoder_offset = vector(0,0)
|
||||||
|
wordline_driver_offset = vector(self.row_decoder.width + self.m2_gap,0)
|
||||||
|
|
||||||
|
self.wordline_driver_inst.place(wordline_driver_offset)
|
||||||
|
self.row_decoder_inst.place(row_decoder_offset)
|
||||||
|
|
||||||
|
self.height = self.row_decoder.height
|
||||||
|
self.width = self.wordline_driver_inst.rx()
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
# See LICENSE for licensing information.
|
# See LICENSE for licensing information.
|
||||||
#
|
#
|
||||||
# Copyright (c) 2016-2019 Regents of the University of California and The Board
|
# Copyright (c) 2016-2019 Regents of the University of California
|
||||||
# of Regents for the Oklahoma Agricultural and Mechanical College
|
|
||||||
# (acting for and on behalf of Oklahoma State University)
|
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
import sys
|
import sys
|
||||||
|
|
@ -16,7 +14,7 @@ from globals import OPTS
|
||||||
|
|
||||||
class port_data(design.design):
|
class port_data(design.design):
|
||||||
"""
|
"""
|
||||||
Create the data port (column mux, sense amps, write driver, etc.)
|
Create the data port (column mux, sense amps, write driver, etc.) for the given port number.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, sram_config, port, name=""):
|
def __init__(self, sram_config, port, name=""):
|
||||||
|
|
@ -25,9 +23,9 @@ class port_data(design.design):
|
||||||
self.port = port
|
self.port = port
|
||||||
|
|
||||||
if name == "":
|
if name == "":
|
||||||
name = "bank_{0}_{1}".format(self.word_size, self.num_words)
|
name = "port_data_{0}".format(self.port)
|
||||||
design.design.__init__(self, name)
|
design.design.__init__(self, name)
|
||||||
debug.info(2, "create sram of size {0} with {1} words".format(self.word_size,self.num_words))
|
debug.info(2, "create data port of size {0} with {1} words per row".format(self.word_size,self.words_per_row))
|
||||||
|
|
||||||
self.create_netlist()
|
self.create_netlist()
|
||||||
if not OPTS.netlist_only:
|
if not OPTS.netlist_only:
|
||||||
|
|
@ -37,7 +35,7 @@ class port_data(design.design):
|
||||||
|
|
||||||
|
|
||||||
def create_netlist(self):
|
def create_netlist(self):
|
||||||
self.compute_sizes()
|
self.precompute_constants()
|
||||||
self.add_pins()
|
self.add_pins()
|
||||||
self.add_modules()
|
self.add_modules()
|
||||||
self.create_instances()
|
self.create_instances()
|
||||||
|
|
@ -72,7 +70,7 @@ class port_data(design.design):
|
||||||
self.DRC_LVS()
|
self.DRC_LVS()
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
""" Adding pins for Bank module"""
|
""" Adding pins for port address module"""
|
||||||
for bit in range(self.num_cols):
|
for bit in range(self.num_cols):
|
||||||
self.add_pin(self.bl_names[self.port]+"_{0}".format(bit),"INOUT")
|
self.add_pin(self.bl_names[self.port]+"_{0}".format(bit),"INOUT")
|
||||||
self.add_pin(self.br_names[self.port]+"_{0}".format(bit),"INOUT")
|
self.add_pin(self.br_names[self.port]+"_{0}".format(bit),"INOUT")
|
||||||
|
|
@ -161,7 +159,7 @@ class port_data(design.design):
|
||||||
self.column_mux_array = None
|
self.column_mux_array = None
|
||||||
|
|
||||||
|
|
||||||
if self.port in self.write_ports or self.port in self.readwrite_ports:
|
if self.port in self.write_ports:
|
||||||
self.write_driver_array = factory.create(module_type="write_driver_array",
|
self.write_driver_array = factory.create(module_type="write_driver_array",
|
||||||
columns=self.num_cols,
|
columns=self.num_cols,
|
||||||
word_size=self.word_size)
|
word_size=self.word_size)
|
||||||
|
|
@ -170,11 +168,8 @@ class port_data(design.design):
|
||||||
self.write_driver_array = None
|
self.write_driver_array = None
|
||||||
|
|
||||||
|
|
||||||
def compute_sizes(self):
|
def precompute_constants(self):
|
||||||
""" Computes the required sizes to create the bank """
|
""" Get some preliminary data ready """
|
||||||
|
|
||||||
self.num_cols = int(self.words_per_row*self.word_size)
|
|
||||||
self.num_rows = int(self.num_words / self.words_per_row)
|
|
||||||
|
|
||||||
# The central bus is the column address (one hot) and row address (binary)
|
# The central bus is the column address (one hot) and row address (binary)
|
||||||
if self.col_addr_size>0:
|
if self.col_addr_size>0:
|
||||||
|
|
@ -182,6 +177,7 @@ class port_data(design.design):
|
||||||
else:
|
else:
|
||||||
self.num_col_addr_lines = 0
|
self.num_col_addr_lines = 0
|
||||||
|
|
||||||
|
|
||||||
# A space for wells or jogging m2 between modules
|
# A space for wells or jogging m2 between modules
|
||||||
self.m2_gap = max(2*drc("pwell_to_nwell") + drc("well_enclosure_active"),
|
self.m2_gap = max(2*drc("pwell_to_nwell") + drc("well_enclosure_active"),
|
||||||
3*self.m2_pitch)
|
3*self.m2_pitch)
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ class sram_config:
|
||||||
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."""
|
||||||
|
|
||||||
self.bitcell = factory.create(module_type="bitcell")
|
bitcell = factory.create(module_type="bitcell")
|
||||||
|
|
||||||
|
|
||||||
debug.check(self.num_banks in [1,2,4], "Valid number of banks are 1 , 2 and 4.")
|
debug.check(self.num_banks in [1,2,4], "Valid number of banks are 1 , 2 and 4.")
|
||||||
|
|
@ -52,11 +52,11 @@ class sram_config:
|
||||||
# If this was hard coded, don't dynamically compute it!
|
# If this was hard coded, don't dynamically compute it!
|
||||||
if not self.words_per_row:
|
if not self.words_per_row:
|
||||||
# Compute the area of the bitcells and estimate a square bank (excluding auxiliary circuitry)
|
# Compute the area of the bitcells and estimate a square bank (excluding auxiliary circuitry)
|
||||||
self.bank_area = self.bitcell.width*self.bitcell.height*self.num_bits_per_bank
|
self.bank_area = bitcell.width*bitcell.height*self.num_bits_per_bank
|
||||||
self.bank_side_length = sqrt(self.bank_area)
|
self.bank_side_length = sqrt(self.bank_area)
|
||||||
|
|
||||||
# Estimate the words per row given the height of the bitcell and the square side length
|
# Estimate the words per row given the height of the bitcell and the square side length
|
||||||
self.tentative_num_cols = int(self.bank_side_length/self.bitcell.width)
|
self.tentative_num_cols = int(self.bank_side_length/bitcell.width)
|
||||||
self.words_per_row = self.estimate_words_per_row(self.tentative_num_cols, self.word_size)
|
self.words_per_row = self.estimate_words_per_row(self.tentative_num_cols, self.word_size)
|
||||||
|
|
||||||
# Estimate the number of rows given the tentative words per row
|
# Estimate the number of rows given the tentative words per row
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# See LICENSE for licensing information.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016-2019 Regents of the University of California
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
import unittest
|
||||||
|
from testutils import *
|
||||||
|
import sys,os
|
||||||
|
sys.path.append(os.getenv("OPENRAM_HOME"))
|
||||||
|
import globals
|
||||||
|
from globals import OPTS
|
||||||
|
from sram_factory import factory
|
||||||
|
import debug
|
||||||
|
|
||||||
|
class port_address_test(openram_test):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
||||||
|
|
||||||
|
debug.info(1, "Port address 16 rows")
|
||||||
|
a = factory.create("port_address", cols=16, rows=16)
|
||||||
|
self.local_check(a)
|
||||||
|
|
||||||
|
globals.end_openram()
|
||||||
|
|
||||||
|
# run the test from the command line
|
||||||
|
if __name__ == "__main__":
|
||||||
|
(OPTS, args) = globals.parse_args()
|
||||||
|
del sys.argv[1:]
|
||||||
|
header(__file__, OPTS.tech_name)
|
||||||
|
unittest.main(testRunner=debugTestRunner())
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# See LICENSE for licensing information.
|
# See LICENSE for licensing information.
|
||||||
#
|
#
|
||||||
# Copyright (c) 2016-2019 Regents of the University of California and The Board
|
# Copyright (c) 2016-2019 Regents of the University of California
|
||||||
# of Regents for the Oklahoma Agricultural and Mechanical College
|
|
||||||
# (acting for and on behalf of Oklahoma State University)
|
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
import unittest
|
import unittest
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue