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
2022-12-30 09:35:15 +01:00
self . read_binary ( word_size = word_size , data_file = data_file )
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 ,
"""
def read_binary ( self , data_file , word_size = 2 , endian = " big " ) :
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
chunked_data = [ ]
for i in range ( 0 , len ( bin_data ) , bits_per_row ) :
word = bin_data [ i : i + bits_per_row ]
if len ( word ) < bits_per_row :
word = [ 0 ] * ( bits_per_row - len ( word ) ) + word
chunked_data . append ( word )
if endian == " big " :
chunked_data . reverse ( )
self . data = chunked_data
self . cols = bits_per_row
self . rows = int ( num_words / ( self . words_per_row ) )
2023-02-01 23:49:59 +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 ) )
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
2022-12-30 09:35:15 +01:00
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 ( )
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 " )
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 ,
cols = self . cols )
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 ,
cols = 1 ,
invert_outputs = True )
self . control_logic = factory . create ( module_type = " rom_control_logic " ,
num_outputs = ( self . rows + self . cols + self . words_per_row ) * 0.5 ,
clk_fanout = ( self . col_bits + self . row_bits ) * 2 ,
2023-02-01 23:49:59 +01:00
height = self . column_decode . height )
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 ) ]
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-01 23:49:59 +01:00
row_decode_pins = addr_msb + wordlines + prechrg + clk + vdd + gnd
col_decode_pins = addr_lsb + select_lines + prechrg + clk + vdd + gnd
2022-12-09 23:25:11 +01:00
2023-02-01 23:49:59 +01:00
col_mux_pins = bitlines + select_lines + outputs + 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 )
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 ( )
self . place_col_mux ( )
2023-01-23 03:34:11 +01:00
self . place_col_decoder ( )
self . place_control_logic ( )
2023-01-17 01:15:03 +01:00
def place_row_decoder ( self ) :
2023-01-23 03:34:11 +01:00
self . decode_offset = vector ( 0 , self . control_inst . height - self . decode_array . control_array . 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 ) ) )
def place_control_logic ( self ) :
2023-01-23 03:34:11 +01:00
self . control_offset = vector ( self . control_inst . width + self . decode_array . control_array . width + 2 * ( self . route_layer_pitch + self . route_layer_width ) , self . col_decode_inst . by ( ) + self . control_logic . height )
self . control_inst . place ( offset = self . control_offset , mirror = " XY " )
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-01 23:49:59 +01:00
mux_y_offset = self . array_inst . by ( ) - self . mux_inst . height - 5 * self . route_layer_pitch
2022-12-09 23:25:11 +01:00
2023-01-23 03:34:11 +01:00
mux_x_offset = self . array_inst . get_pin ( " bl_0_0 " ) . cx ( ) - self . mux_inst . get_pin ( " bl_0 " ) . cx ( )
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-01-23 03:34:11 +01:00
# def create_wl_bus(self):
# bus_x = self.decode_inst.width + ( drc["minwidth_{}".format(self.bus_layer)] + 1.5 * drc["{0}_to_{0}".format(self.bus_layer)] )
# bus_y = self.array_inst.by() + self.bus_layer_pitch + self.bus_layer_width
# self.wl_interconnects = []
2022-12-30 09:35:15 +01:00
2023-01-23 03:34:11 +01:00
# for wl in range(self.rows):
# self.wl_interconnects.append("wl_interconnect_{}".format(wl))
2022-12-09 23:25:11 +01:00
2023-01-23 03:34:11 +01:00
# self.wl_bus = self.create_vertical_bus(self.bus_layer, vector(bus_x, bus_y), self.wl_interconnects, self.decode_inst.uy() - self.array_inst.by() )
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 )
self . add_via_stack_center ( start , self . route_layer , self . interconnect_layer )
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 " )
row_decode_prechrg = self . decode_inst . get_pin ( " precharge " )
col_decode_prechrg = self . col_decode_inst . get_pin ( " precharge " )
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
end = vector ( row_decode_prechrg . cx ( ) - 0.5 * self . interconnect_layer_width , prechrg_control . cy ( ) )
self . add_segment_center ( self . interconnect_layer , prechrg_control . center ( ) , end )
2022-12-30 09:35:15 +01:00
2023-01-23 03:34:11 +01:00
start = end + vector ( 0.5 * self . interconnect_layer_width , 0 )
self . add_segment_center ( self . interconnect_layer , start , row_decode_prechrg . center ( ) )
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
start = row_decode_prechrg . center ( ) - vector ( 0 , self . route_layer_pitch + 2 * self . route_layer_width )
mid = vector ( col_decode_prechrg . cx ( ) , start . y )
end = vector ( col_decode_prechrg . cx ( ) , 0.5 * ( self . col_decode_inst . uy ( ) + mid . y ) )
self . add_path ( self . route_stack [ 0 ] , [ start , mid , end ] )
self . add_via_stack_center ( from_layer = self . route_stack [ 0 ] ,
to_layer = col_decode_prechrg . layer ,
offset = end )
self . add_segment_center ( col_decode_prechrg . layer , end , col_decode_prechrg . center ( ) )
# Route precharge to main array
end = vector ( col_decode_prechrg . cx ( ) , array_prechrg . cy ( ) )
self . add_segment_center ( self . route_stack [ 0 ] , array_prechrg . center ( ) , end )
def route_clock ( self ) :
clk_out = self . control_inst . get_pin ( " clk_out " )
row_decode_clk = self . decode_inst . get_pin ( " clk " )
col_decode_clk = self . col_decode_inst . get_pin ( " clk " )
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
end = row_decode_clk . rc ( ) + 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-01-23 03:34:11 +01:00
self . add_via_stack_center ( from_layer = self . route_stack [ 2 ] ,
to_layer = row_decode_clk . layer ,
offset = end )
2022-12-30 09:35:15 +01:00
2023-01-23 03:34:11 +01:00
self . add_segment_center ( row_decode_clk . layer , end , 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
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-01-23 03:34:11 +01:00
self . add_via_stack_center ( from_layer = self . route_stack [ 2 ] ,
to_layer = row_decode_clk . layer ,
offset = end )
self . add_segment_center ( col_decode_clk . layer , end , col_decode_clk . lc ( ) )
def route_array_outputs ( self ) :
for i in range ( self . cols ) :
bl_out = self . array_inst . get_pin ( " bl_0_ {} " . format ( i ) ) . center ( )
bl_mux = self . mux_inst . get_pin ( " bl_ {} " . format ( i ) ) . center ( )
self . add_path ( self . array . bitline_layer , [ bl_out , bl_mux ] )
2022-12-30 09:35:15 +01:00
2023-02-01 23:49:59 +01:00
def place_top_level_pins ( self ) :
self . copy_layout_pin ( self . control_inst , " CS " , " CS " )
for i in range ( self . word_size ) :
self . copy_layout_pin ( self . mux_inst , " bl_out_ {} " . format ( i ) , " rom_out_ {} " . format ( i ) )
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 " )
# gnd_start = vector(self.array_inst.get_pins("gnd")[0].cx(),0)
2022-12-30 09:35:15 +01:00
2023-02-01 23:49:59 +01:00
# decode_gnd = self.decode_inst.get_pin("gnd")
# decode_vdd = self.decode_inst.get_pin("vdd")
# array_vdd = self.array_inst.get_pin("vdd")
2022-12-09 23:25:11 +01:00
2023-02-01 23:49:59 +01:00
# # self.add_segment_center("m1", gnd_start, decode_gnd.center())
2022-12-09 23:25:11 +01:00
2023-02-01 23:49:59 +01:00
# self.add_power_pin("gnd", decode_vdd.center())
# self.add_power_pin("vdd", decode_gnd.center())
2022-12-09 23:25:11 +01:00
2023-02-01 23:49:59 +01:00
# vdd_start = vector(array_vdd.lx() + 0.5 * self.via1_space, array_vdd.cy())
# end = vector(decode_vdd.lx(), vdd_start.y)
2022-12-09 23:25:11 +01:00
2023-02-01 23:49:59 +01:00
# self.add_segment_center(self.interconnect_layer, vdd_start, end)
# self.add_via_stack_center(vdd_start, "m1", self.interconnect_layer)
2022-12-09 23:25:11 +01:00
2023-02-01 23:49:59 +01:00
# vdd_start = vector(decode_vdd.cx(), vdd_start.y)
2022-12-09 23:25:11 +01:00
2023-02-01 23:49:59 +01:00
# self.add_segment_center(self.interconnect_layer, vdd_start, decode_vdd.center())
2022-12-09 23:25:11 +01:00