2022-12-09 23:25:11 +01:00
2022-12-30 09:35:15 +01:00
from math import ceil , log , sqrt
2022-12-13 01:35:23 +01:00
from openram . base import vector
from openram . base import design
2023-02-01 23:49:59 +01:00
from openram import OPTS , debug
2022-12-13 01:35:23 +01:00
from openram . sram_factory import factory
2023-01-17 01:15:03 +01:00
from openram . tech import drc , layer
2022-12-09 23:25:11 +01:00
class rom_base_bank ( design ) :
2023-01-17 01:15:03 +01:00
"""
Rom data bank with row and column decoder + control logic
word size is in bytes
"""
2023-02-01 23:49:59 +01:00
def __init__ ( self , strap_spacing = 0 , data_file = None , name = " " , word_size = 2 ) :
super ( ) . __init__ ( name = name )
2023-01-17 01:15:03 +01:00
self . word_size = word_size * 8
2023-02-27 23:48:10 +01:00
self . read_binary ( word_size = word_size , data_file = data_file , scramble_bits = True , endian = " little " )
2022-12-09 23:25:11 +01:00
2022-12-30 09:35:15 +01:00
self . num_outputs = self . rows
self . num_inputs = ceil ( log ( self . rows , 2 ) )
2023-01-17 01:15:03 +01:00
self . col_bits = ceil ( log ( self . words_per_row , 2 ) )
self . row_bits = self . num_inputs
2022-12-09 23:25:11 +01:00
2022-12-30 09:35:15 +01:00
# self.data = [[0, 1, 0, 1], [1, 1, 1, 1], [1, 1, 0, 0], [0, 0, 1, 0]]
self . strap_spacing = strap_spacing
2023-01-23 03:34:11 +01:00
self . tap_spacing = 8
2022-12-30 09:35:15 +01:00
self . interconnect_layer = " m1 "
2023-01-23 03:34:11 +01:00
self . bitline_layer = " m1 "
self . wordline_layer = " m2 "
2022-12-30 09:35:15 +01:00
2023-02-01 23:49:59 +01:00
2023-01-23 03:34:11 +01:00
if " li " in layer :
self . route_stack = self . m1_stack
else :
self . route_stack = self . m2_stack
self . route_layer = self . route_stack [ 0 ]
2022-12-09 23:25:11 +01:00
self . setup_layout_constants ( )
self . create_netlist ( )
2023-02-01 23:49:59 +01:00
if not OPTS . netlist_only :
self . create_layout ( )
2022-12-30 09:35:15 +01:00
"""
Reads a hexadecimal file from a given directory to be used as the data written to the ROM
endian is either " big " or " little "
word_size is the number of bytes per word
sets the row and column size based on the size of binary input , tries to keep array as square as possible ,
"""
2023-02-27 23:48:10 +01:00
def read_binary ( self , data_file , word_size = 2 , endian = " big " , scramble_bits = False ) :
2023-02-01 23:49:59 +01:00
# Read data as hexidecimal text file
2022-12-30 09:35:15 +01:00
hex_file = open ( data_file , ' r ' )
hex_data = hex_file . read ( )
2023-02-01 23:49:59 +01:00
# Convert from hex into an int
data_int = int ( hex_data , 16 )
# Then from int into a right aligned, zero padded string
bin_string = bin ( data_int ) [ 2 : ] . zfill ( len ( hex_data ) * 4 )
# Then turn the string into a list of ints
bin_data = list ( bin_string )
2022-12-30 09:35:15 +01:00
bin_data = [ int ( x ) for x in bin_data ]
# data size in bytes
data_size = len ( bin_data ) / 8
num_words = int ( data_size / word_size )
bytes_per_col = sqrt ( num_words )
self . words_per_row = int ( ceil ( bytes_per_col / ( 2 * word_size ) ) )
bits_per_row = self . words_per_row * word_size * 8
2023-02-27 23:48:10 +01:00
self . cols = bits_per_row
self . rows = int ( num_words / ( self . words_per_row ) )
2022-12-30 09:35:15 +01:00
chunked_data = [ ]
for i in range ( 0 , len ( bin_data ) , bits_per_row ) :
2023-02-27 23:48:10 +01:00
row_data = bin_data [ i : i + bits_per_row ]
if len ( row_data ) < bits_per_row :
row_data = [ 0 ] * ( bits_per_row - len ( row_data ) ) + row_data
chunked_data . append ( row_data )
# if endian == "big":
2022-12-30 09:35:15 +01:00
self . data = chunked_data
2023-02-27 23:48:10 +01:00
if scramble_bits :
scrambled_chunked = [ ]
for row_data in chunked_data :
scambled_data = [ ]
for bit in range ( self . word_size ) :
for word in range ( self . words_per_row ) :
scambled_data . append ( row_data [ bit + word * self . word_size ] )
scrambled_chunked . append ( scambled_data )
self . data = scrambled_chunked
# self.data.reverse()
2023-02-01 23:49:59 +01:00
2023-02-27 23:48:10 +01:00
debug . info ( 1 , " Read rom binary: length {0} bytes, {1} words, set number of cols to {2} , rows to {3} , with {4} words per row " . format ( data_size , num_words , self . cols , self . rows , self . words_per_row ) )
# self.print_data(chunked_data)
# print("Scrambled")
# self.print_data(scrambled_chunked)
# self.print_word(self.data, 0, 0)
# self.print_word(self.data, 0, 1)
# self.print_word(self.data, 0, 2)
# self.print_word(self.data, 0, 3)
2022-12-30 09:35:15 +01:00
# print("hex: {0}, binary: {1}, chunked: {2}".format(hex_data, bin_data, chunked_data))
2022-12-09 23:25:11 +01:00
2023-02-27 23:48:10 +01:00
def print_data ( self , data_array ) :
for row in range ( len ( data_array ) ) :
print ( data_array [ row ] )
2022-12-30 09:35:15 +01:00
2023-02-27 23:48:10 +01:00
def print_word ( self , data_array , bl , word ) :
for bit in range ( self . word_size ) :
print ( data_array [ bl ] [ word + self . words_per_row * bit ] , end = " " )
print ( " " )
2022-12-09 23:25:11 +01:00
def create_netlist ( self ) :
self . add_modules ( )
2023-02-01 23:49:59 +01:00
self . add_pins ( )
2023-01-23 03:34:11 +01:00
2022-12-09 23:25:11 +01:00
def create_layout ( self ) :
2023-02-01 23:49:59 +01:00
print ( " Creating ROM bank instances " )
self . create_instances ( )
2023-01-23 03:34:11 +01:00
print ( " Placing ROM bank instances " )
2022-12-09 23:25:11 +01:00
self . place_instances ( )
2023-01-23 03:34:11 +01:00
print ( " Routing decoders to array " )
2022-12-09 23:25:11 +01:00
self . route_decode_outputs ( )
2023-01-23 03:34:11 +01:00
print ( " Routing precharge signal " )
self . route_precharge ( )
print ( " Routing clock signal " )
self . route_clock ( )
self . route_array_outputs ( )
2023-02-01 23:49:59 +01:00
self . place_top_level_pins ( )
self . route_supplies ( )
2023-02-04 02:21:35 +01:00
self . route_output_buffers ( )
2022-12-09 23:25:11 +01:00
self . height = self . array_inst . height
self . width = self . array_inst . width
self . add_boundary ( )
def setup_layout_constants ( self ) :
2023-01-23 03:34:11 +01:00
self . route_layer_width = drc [ " minwidth_ {} " . format ( self . route_stack [ 0 ] ) ]
self . route_layer_pitch = drc [ " {0} _to_ {0} " . format ( self . route_stack [ 0 ] ) ]
2022-12-30 09:35:15 +01:00
self . interconnect_layer_width = drc [ " minwidth_ {} " . format ( self . interconnect_layer ) ]
self . interconnect_layer_pitch = drc [ " {0} _to_ {0} " . format ( self . interconnect_layer ) ]
def add_pins ( self ) :
2022-12-09 23:25:11 +01:00
2023-01-23 03:34:11 +01:00
self . add_pin ( " clk " , " INPUT " )
2022-12-30 09:35:15 +01:00
self . add_pin ( " CS " , " INPUT " )
2023-02-01 23:49:59 +01:00
for i in range ( self . row_bits + self . col_bits ) :
2022-12-30 09:35:15 +01:00
self . add_pin ( " addr_ {} " . format ( i ) , " INPUT " )
out_pins = [ ]
2023-02-01 23:49:59 +01:00
for j in range ( self . word_size ) :
2022-12-30 09:35:15 +01:00
out_pins . append ( " rom_out_ {} " . format ( j ) )
self . add_pin_list ( out_pins , " OUTPUT " )
self . add_pin ( " vdd " , " POWER " )
self . add_pin ( " gnd " , " GROUND " )
2022-12-09 23:25:11 +01:00
def add_modules ( self ) :
2023-01-23 03:34:11 +01:00
print ( " Creating bank modules " )
2023-02-27 23:48:10 +01:00
# TODO: provide technology-specific calculation of these parameters
# in sky130 the address control buffer is composed of 2 size 2 NAND gates,
# with a beta of 3, each of these gates has gate capacitance of 2 min sized inverters, therefor a load of 4
addr_control_buffer_effort = 4
# a single min sized nmos makes up 1/4 of the input capacitance of a min sized inverter
bitcell_effort = 0.25
# Takes into account inverter sizing
wordline_effort = bitcell_effort * 0.5
# a single min sized pmos plus a single min sized nmos have approximately half the gate capacitance of a min inverter
# an additional 0.2 accounts for the long wire capacitance and add delay to gaurentee the read timing
precharge_cell_effort = 0.5 + 0.2
2023-01-23 03:34:11 +01:00
self . array = factory . create ( module_type = " rom_base_array " ,
cols = self . cols ,
rows = self . rows ,
strap_spacing = self . strap_spacing ,
bitmap = self . data ,
bitline_layer = self . bitline_layer ,
wordline_layer = self . wordline_layer ,
pitch_match = True ,
tap_spacing = self . tap_spacing )
self . decode_array = factory . create ( module_name = " rom_row_decode " ,
module_type = " rom_decoder " ,
num_outputs = self . rows ,
strap_spacing = self . strap_spacing ,
route_layer = self . route_layer ,
2023-02-27 23:48:10 +01:00
fanout = ( self . cols ) * wordline_effort )
2023-02-01 23:49:59 +01:00
2023-01-23 03:34:11 +01:00
self . column_mux = factory . create ( module_type = " rom_column_mux_array " ,
columns = self . cols ,
word_size = self . word_size ,
2023-02-01 23:49:59 +01:00
tap_spacing = self . strap_spacing ,
bitline_layer = self . interconnect_layer ,
input_layer = self . bitline_layer )
2023-01-23 03:34:11 +01:00
self . column_decode = factory . create ( module_name = " rom_column_decode " ,
module_type = " rom_decoder " ,
num_outputs = self . words_per_row ,
strap_spacing = self . strap_spacing ,
route_layer = self . route_layer ,
2023-02-27 23:48:10 +01:00
fanout = 2 ,
2023-01-23 03:34:11 +01:00
invert_outputs = True )
self . control_logic = factory . create ( module_type = " rom_control_logic " ,
2023-02-27 23:48:10 +01:00
num_outputs = ( self . cols + self . words_per_row * precharge_cell_effort ) \
+ ( addr_control_buffer_effort * self . col_bits ) ,
clk_fanout = ( self . row_bits * addr_control_buffer_effort ) + ( precharge_cell_effort * self . rows ) ,
2023-02-01 23:49:59 +01:00
height = self . column_decode . height )
2023-02-03 08:39:08 +01:00
2023-02-27 23:48:10 +01:00
self . bitline_inv = factory . create ( module_type = " rom_wordline_driver_array " ,
module_name = " rom_bitline_inverter " ,
rows = self . cols ,
fanout = 4 ,
invert_outputs = True ,
tap_spacing = 0 ,
flip_io = True )
self . output_inv = factory . create ( module_type = " rom_wordline_driver_array " ,
2023-02-04 02:21:35 +01:00
module_name = " rom_output_buffer " ,
2023-02-03 08:39:08 +01:00
rows = self . word_size ,
2023-02-27 23:48:10 +01:00
fanout = 4 ,
invert_outputs = True )
2023-01-23 03:34:11 +01:00
2022-12-09 23:25:11 +01:00
def create_instances ( self ) :
2023-01-17 01:15:03 +01:00
gnd = [ " gnd " ]
vdd = [ " vdd " ]
prechrg = [ " precharge " ]
2023-01-23 03:34:11 +01:00
clk = [ " clk_int " ]
2022-12-09 23:25:11 +01:00
2023-02-01 23:49:59 +01:00
bitlines = [ " bl_ {} " . format ( bl ) for bl in range ( self . cols ) ]
wordlines = [ " wl_ {} " . format ( wl ) for wl in range ( self . rows ) ]
2022-12-09 23:25:11 +01:00
2023-02-01 23:49:59 +01:00
addr_msb = [ " addr_ {} " . format ( addr + self . col_bits ) for addr in range ( self . row_bits ) ]
addr_lsb = [ " addr_ {} " . format ( addr ) for addr in range ( self . col_bits ) ]
2022-12-09 23:25:11 +01:00
2023-02-01 23:49:59 +01:00
select_lines = [ " word_sel_ {} " . format ( word ) for word in range ( self . words_per_row ) ]
2023-02-03 08:39:08 +01:00
2023-02-27 23:48:10 +01:00
bitline_bar = [ " bl_b_ {} " . format ( bl ) for bl in range ( self . cols ) ]
2023-02-03 08:39:08 +01:00
pre_buf_outputs = [ " rom_out_prebuf_ {} " . format ( bit ) for bit in range ( self . word_size ) ]
2023-02-01 23:49:59 +01:00
outputs = [ " rom_out_ {} " . format ( bl ) for bl in range ( self . word_size ) ]
2022-12-09 23:25:11 +01:00
2023-02-01 23:49:59 +01:00
array_pins = bitlines + wordlines + prechrg + vdd + gnd
2022-12-09 23:25:11 +01:00
2023-02-27 23:48:10 +01:00
row_decode_pins = addr_msb + wordlines + clk + clk + vdd + gnd
col_decode_pins = addr_lsb + select_lines + prechrg + prechrg + vdd + gnd
2022-12-09 23:25:11 +01:00
2023-02-27 23:48:10 +01:00
col_mux_pins = bitline_bar + select_lines + pre_buf_outputs + gnd
2023-02-03 08:39:08 +01:00
2023-02-27 23:48:10 +01:00
bitline_inv_pins = bitlines + bitline_bar + vdd + gnd
output_buf_pins = pre_buf_outputs + outputs + vdd + gnd
2023-01-17 01:15:03 +01:00
2022-12-09 23:25:11 +01:00
self . array_inst = self . add_inst ( name = " rom_bit_array " , mod = self . array )
self . connect_inst ( array_pins )
2023-01-17 01:15:03 +01:00
self . decode_inst = self . add_inst ( name = " rom_row_decoder " , mod = self . decode_array )
2023-02-01 23:49:59 +01:00
self . connect_inst ( row_decode_pins )
2022-12-09 23:25:11 +01:00
2022-12-30 09:35:15 +01:00
self . control_inst = self . add_inst ( name = " rom_control " , mod = self . control_logic )
2023-01-23 03:34:11 +01:00
self . connect_inst ( [ " clk " , " CS " , " precharge " , " clk_int " , " vdd " , " gnd " ] )
2022-12-30 09:35:15 +01:00
2023-01-17 01:15:03 +01:00
self . mux_inst = self . add_inst ( name = " rom_column_mux " , mod = self . column_mux )
self . connect_inst ( col_mux_pins )
self . col_decode_inst = self . add_inst ( name = " rom_column_decoder " , mod = self . column_decode )
self . connect_inst ( col_decode_pins )
2023-02-27 23:48:10 +01:00
self . bitline_inv_inst = self . add_inst ( name = " rom_bitline_inverter " , mod = self . bitline_inv )
self . connect_inst ( bitline_inv_pins )
self . output_inv_inst = self . add_inst ( name = " rom_output_inverter " , mod = self . output_inv )
self . connect_inst ( output_buf_pins )
2023-02-03 08:39:08 +01:00
2022-12-09 23:25:11 +01:00
def place_instances ( self ) :
2023-01-17 01:15:03 +01:00
self . place_row_decoder ( )
self . place_data_array ( )
2023-02-27 23:48:10 +01:00
self . place_bitline_inverter ( )
2023-01-17 01:15:03 +01:00
self . place_col_mux ( )
2023-01-23 03:34:11 +01:00
self . place_col_decoder ( )
self . place_control_logic ( )
2023-02-03 08:39:08 +01:00
self . place_output_buffer ( )
2023-01-17 01:15:03 +01:00
def place_row_decoder ( self ) :
2023-02-27 23:48:10 +01:00
self . decode_offset = vector ( 0 , self . control_inst . height )
2023-01-17 01:15:03 +01:00
self . decode_inst . place ( offset = self . decode_offset )
def place_data_array ( self ) :
# We approximate the correct position for the array
2022-12-30 09:35:15 +01:00
array_x = self . decode_inst . width + ( 2 ) * ( self . route_layer_width + self . route_layer_pitch )
2023-01-17 01:15:03 +01:00
array_y = self . decode_array . buf_inst . height - self . array . precharge_inst . cy ( ) - self . array . zero_cell . height * 0.5
2022-12-09 23:25:11 +01:00
self . array_offset = vector ( array_x , array_y )
2023-01-17 01:15:03 +01:00
self . array_inst . place ( offset = self . array_offset )
2022-12-09 23:25:11 +01:00
2023-01-17 01:15:03 +01:00
# now move array to correct alignment with decoder
array_align = self . decode_inst . get_pin ( " wl_0 " ) . cy ( ) - self . array_inst . get_pin ( " wl_0_0 " ) . cy ( )
self . array_inst . place ( offset = ( self . array_offset + vector ( 0 , array_align ) ) )
2023-02-27 23:48:10 +01:00
def place_bitline_inverter ( self ) :
self . bitline_inv_inst . place ( offset = [ 0 , 0 ] , rotate = 90 )
inv_y_offset = self . array_inst . by ( ) - self . bitline_inv_inst . width - 2 * self . m1_pitch
2023-01-23 03:34:11 +01:00
2023-02-27 23:48:10 +01:00
inv_x_offset = self . array_inst . get_pin ( " bl_0_0 " ) . cx ( ) - self . bitline_inv_inst . get_pin ( " out_0 " ) . cx ( )
self . inv_offset = vector ( inv_x_offset , inv_y_offset )
self . bitline_inv_inst . place ( offset = self . inv_offset , rotate = 90 )
def place_control_logic ( self ) :
2023-01-23 03:34:11 +01:00
2023-02-27 23:48:10 +01:00
self . control_offset = vector ( self . col_decode_inst . lx ( ) - self . control_inst . width - 3 * self . m1_pitch , self . decode_inst . by ( ) - self . control_logic . height - self . m1_pitch )
self . control_inst . place ( offset = self . control_offset )
2022-12-30 09:35:15 +01:00
2023-01-17 01:15:03 +01:00
def place_col_decoder ( self ) :
2023-01-23 03:34:11 +01:00
col_decode_y = self . mux_inst . get_pin ( " sel_0 " ) . cy ( ) - self . col_decode_inst . get_pin ( " wl_0 " ) . cy ( )
self . col_decode_offset = vector ( self . decode_inst . width - self . col_decode_inst . width , col_decode_y )
2023-01-17 01:15:03 +01:00
self . col_decode_inst . place ( offset = self . col_decode_offset )
2022-12-09 23:25:11 +01:00
2023-01-17 01:15:03 +01:00
def place_col_mux ( self ) :
2023-02-27 23:48:10 +01:00
mux_y_offset = self . bitline_inv_inst . by ( ) - self . mux_inst . height - 5 * self . route_layer_pitch
2022-12-09 23:25:11 +01:00
2023-02-27 23:48:10 +01:00
mux_x_offset = self . bitline_inv_inst . get_pin ( " out_0 " ) . cx ( ) - self . mux_inst . get_pin ( " bl_0 " ) . cx ( )
2023-01-23 03:34:11 +01:00
self . mux_offset = vector ( mux_x_offset , mux_y_offset )
2023-01-17 01:15:03 +01:00
self . mux_inst . place ( offset = self . mux_offset )
2023-02-03 08:39:08 +01:00
def place_output_buffer ( self ) :
2023-02-27 23:48:10 +01:00
output_x = self . col_decode_inst . rx ( ) + self . output_inv_inst . height
output_y = self . mux_inst . by ( ) - self . word_size * self . m1_pitch
self . output_inv_offset = vector ( output_x , output_y )
self . output_inv_inst . place ( offset = self . output_inv_offset , rotate = 270 )
2023-01-17 01:15:03 +01:00
2022-12-09 23:25:11 +01:00
def route_decode_outputs ( self ) :
2023-01-23 03:34:11 +01:00
# for the row decoder
2023-01-17 01:15:03 +01:00
route_pins = [ self . array_inst . get_pin ( " wl_0_ {} " . format ( wl ) ) for wl in range ( self . rows ) ]
decode_pins = [ self . decode_inst . get_pin ( " wl_ {} " . format ( wl ) ) for wl in range ( self . rows ) ]
route_pins . extend ( decode_pins )
self . connect_row_pins ( self . interconnect_layer , route_pins , round = True )
2022-12-09 23:25:11 +01:00
2023-01-23 03:34:11 +01:00
# then for the column decoder
col_decode_pins = [ self . col_decode_inst . get_pin ( " wl_ {} " . format ( wl ) ) for wl in range ( self . words_per_row ) ]
sel_pins = [ self . mux_inst . get_pin ( " sel_ {} " . format ( wl ) ) for wl in range ( self . words_per_row ) ]
sel_pins . extend ( col_decode_pins )
2023-02-01 23:49:59 +01:00
self . connect_row_pins ( self . wordline_layer , sel_pins , round = True )
2022-12-09 23:25:11 +01:00
def route_array_inputs ( self ) :
for wl in range ( self . rows ) :
array_wl = self . array . wordline_names [ 0 ] [ wl ]
array_wl_pin = self . array_inst . get_pin ( array_wl )
wl_bus_wire = self . wl_bus [ self . wl_interconnects [ wl ] ]
end = array_wl_pin . center ( )
start = vector ( wl_bus_wire . cx ( ) , end . y )
self . add_segment_center ( self . interconnect_layer , start , end )
2023-01-23 03:34:11 +01:00
def route_precharge ( self ) :
2022-12-30 09:35:15 +01:00
2023-01-23 03:34:11 +01:00
prechrg_control = self . control_inst . get_pin ( " prechrg " )
2023-02-27 23:48:10 +01:00
col_decode_prechrg = self . col_decode_inst . get_pin ( " precharge_r " )
col_decode_clk = self . col_decode_inst . get_pin ( " clk " )
2022-12-30 09:35:15 +01:00
array_prechrg = self . array_inst . get_pin ( " precharge " )
2023-01-23 03:34:11 +01:00
# Route precharge signal to the row decoder
2023-02-27 23:48:10 +01:00
# end = vector(row_decode_prechrg.cx() - 0.5 * self.interconnect_layer_width, prechrg_control.cy())
2023-01-23 03:34:11 +01:00
2023-02-27 23:48:10 +01:00
# self.add_segment_center(self.interconnect_layer, prechrg_control.center(), end)
2022-12-30 09:35:15 +01:00
2023-02-27 23:48:10 +01:00
# start = end + vector(0.5 * self.interconnect_layer_width, 0)
# self.add_segment_center(self.interconnect_layer, start, row_decode_prechrg.center())
2023-01-23 03:34:11 +01:00
self . add_via_stack_center ( from_layer = self . route_stack [ 0 ] ,
to_layer = prechrg_control . layer ,
offset = prechrg_control . center ( ) )
# Route precharge to col decoder
2023-02-27 23:48:10 +01:00
start = prechrg_control . center ( )
mid1 = vector ( self . control_inst . rx ( ) , prechrg_control . cy ( ) )
mid2 = vector ( self . control_inst . rx ( ) , col_decode_prechrg . cy ( ) )
end = col_decode_prechrg . center ( )
self . add_path ( self . route_stack [ 0 ] , [ start , mid1 , mid2 , end ] )
2023-01-23 03:34:11 +01:00
self . add_via_stack_center ( from_layer = self . route_stack [ 0 ] ,
to_layer = col_decode_prechrg . layer ,
offset = end )
2023-02-27 23:48:10 +01:00
start = mid1
mid1 = vector ( self . control_inst . rx ( ) , start . y )
mid2 = vector ( mid1 . x , col_decode_clk . cy ( ) )
end = col_decode_clk . center ( )
self . add_path ( self . route_stack [ 0 ] , [ start , mid1 , mid2 , end ] )
# self.add_segment_center(col_decode_prechrg.layer, end, col_decode_prechrg.center())
2023-01-23 03:34:11 +01:00
# Route precharge to main array
2023-02-27 23:48:10 +01:00
# end = vector(col_decode_prechrg.cx(), array_prechrg.cy())
mid = vector ( col_decode_prechrg . cx ( ) , array_prechrg . cy ( ) )
self . add_path ( self . route_stack [ 0 ] , [ array_prechrg . center ( ) , mid , col_decode_prechrg . center ( ) ] )
2023-01-23 03:34:11 +01:00
def route_clock ( self ) :
clk_out = self . control_inst . get_pin ( " clk_out " )
row_decode_clk = self . decode_inst . get_pin ( " clk " )
2023-02-27 23:48:10 +01:00
2023-01-23 03:34:11 +01:00
self . add_via_stack_center ( from_layer = self . route_stack [ 2 ] ,
to_layer = clk_out . layer ,
offset = clk_out . center ( ) )
2022-12-30 09:35:15 +01:00
2023-01-23 03:34:11 +01:00
# Route clock to row decoder
2023-02-27 23:48:10 +01:00
mid = vector ( self . control_inst . rx ( ) + self . m1_pitch , clk_out . cy ( ) )
addr_control_clk = row_decode_clk . rc ( ) + vector ( 2 * self . route_layer_pitch + self . route_layer_width , 0 )
row_decode_prechrg = self . decode_inst . get_pin ( " precharge " )
self . add_path ( self . route_stack [ 2 ] , [ clk_out . center ( ) , mid , addr_control_clk , row_decode_prechrg . center ( ) ] )
2022-12-30 09:35:15 +01:00
2023-01-23 03:34:11 +01:00
self . add_via_stack_center ( from_layer = self . route_stack [ 2 ] ,
to_layer = row_decode_clk . layer ,
2023-02-27 23:48:10 +01:00
offset = addr_control_clk )
2022-12-30 09:35:15 +01:00
2023-02-27 23:48:10 +01:00
self . add_segment_center ( row_decode_clk . layer , addr_control_clk , row_decode_clk . rc ( ) )
2022-12-30 09:35:15 +01:00
2023-01-23 03:34:11 +01:00
# Route clock to column decoder
2023-02-27 23:48:10 +01:00
# end = col_decode_clk.lc() - vector( 2 * self.route_layer_pitch + self.route_layer_width, 0)
# self.add_path(self.route_stack[2], [clk_out.center(), end])
2022-12-30 09:35:15 +01:00
2023-02-27 23:48:10 +01:00
# self.add_via_stack_center(from_layer=self.route_stack[2],
# to_layer=row_decode_clk.layer,
# offset=end)
2023-01-23 03:34:11 +01:00
2023-02-27 23:48:10 +01:00
# self.add_segment_center(col_decode_clk.layer, end, col_decode_clk.lc())
2023-01-23 03:34:11 +01:00
def route_array_outputs ( self ) :
2023-02-27 23:48:10 +01:00
array_out_pins = [ self . array_inst . get_pin ( " bl_0_ {} " . format ( bl ) ) for bl in range ( self . cols ) ]
inv_in_pins = [ self . bitline_inv_inst . get_pin ( " in_ {} " . format ( bl ) ) for bl in range ( self . cols ) ]
inv_out_pins = [ self . bitline_inv_inst . get_pin ( " out_ {} " . format ( bl ) ) for bl in range ( self . cols ) ]
mux_pins = [ self . mux_inst . get_pin ( " bl_ {} " . format ( bl ) ) for bl in range ( self . cols ) ]
self . connect_col_pins ( self . interconnect_layer , array_out_pins + inv_in_pins , round = True , directions = " nonpref " )
self . connect_col_pins ( self . interconnect_layer , inv_out_pins + mux_pins , round = True , directions = " nonpref " )
2023-02-04 02:21:35 +01:00
2023-01-23 03:34:11 +01:00
2022-12-30 09:35:15 +01:00
2023-02-04 02:21:35 +01:00
def route_output_buffers ( self ) :
mux = self . mux_inst
2023-02-27 23:48:10 +01:00
buf = self . output_inv_inst
2023-02-04 02:21:35 +01:00
route_nets = [ [ mux . get_pin ( " bl_out_ {} " . format ( bit ) ) , buf . get_pin ( " in_ {} " . format ( bit ) ) ] for bit in range ( self . word_size ) ]
channel_ll = vector ( route_nets [ 0 ] [ 0 ] . cx ( ) , route_nets [ 0 ] [ 1 ] . cy ( ) + self . m1_pitch * 3 )
self . create_horizontal_channel_route ( netlist = route_nets , offset = channel_ll , layer_stack = self . m1_stack )
# for bit in range(self.word_size):
# mux_pin = self.mux_inst.get_pin("bl_out_{}".format(bit))
# buf_pin = self.output_buf_inst.get_pin("in_{}".format(bit))
# mux_out = vector(mux_pin.cx(), mux_pin.by())
# buf_in = buf_pin.center()
# mid1 = vector(mux_out.x, buf_in.y + bit * self.m2_pitch)
# mid2 = vector(buf_in.x, mid1.y)
# print("start: {0}, mid: {1}, stop: {2}".format(mux_out, mid1, buf_in))
# self.add_path(layer="m2", coordinates=[mux_out, mid1, mid2, buf_in])
2023-02-01 23:49:59 +01:00
def place_top_level_pins ( self ) :
2023-02-04 02:21:35 +01:00
self . copy_layout_pin ( self . control_inst , " CS " )
self . copy_layout_pin ( self . control_inst , " clk_in " , " clk " )
2023-02-01 23:49:59 +01:00
for i in range ( self . word_size ) :
2023-02-27 23:48:10 +01:00
self . copy_layout_pin ( self . output_inv_inst , " out_ {} " . format ( i ) , " rom_out_ {} " . format ( i ) )
2023-02-01 23:49:59 +01:00
for lsb in range ( self . col_bits ) :
name = " addr_ {} " . format ( lsb )
self . copy_layout_pin ( self . col_decode_inst , " A {} " . format ( lsb ) , name )
for msb in range ( self . col_bits , self . row_bits + self . col_bits ) :
name = " addr_ {} " . format ( msb )
pin_num = msb - self . col_bits
self . copy_layout_pin ( self . decode_inst , " A {} " . format ( pin_num ) , name )
2022-12-30 09:35:15 +01:00
2022-12-09 23:25:11 +01:00
2023-02-01 23:49:59 +01:00
2022-12-09 23:25:11 +01:00
def route_supplies ( self ) :
2023-01-23 03:34:11 +01:00
for inst in self . insts :
2023-02-01 23:49:59 +01:00
if not inst . mod . name . __contains__ ( " contact " ) :
self . copy_layout_pin ( inst , " vdd " )
self . copy_layout_pin ( inst , " gnd " )
2022-12-09 23:25:11 +01:00