mirror of https://github.com/VLSIDA/OpenRAM.git
Add check bits. Clean up logic. Move read/write bit check to next cycle.
This commit is contained in:
parent
fe0db68965
commit
fb60b51c72
|
|
@ -82,7 +82,6 @@ class delay(simulation):
|
||||||
def create_read_port_measurement_objects(self):
|
def create_read_port_measurement_objects(self):
|
||||||
"""Create the measurements used for read ports: delays, slews, powers"""
|
"""Create the measurements used for read ports: delays, slews, powers"""
|
||||||
|
|
||||||
import pdb; pdb.set_trace()
|
|
||||||
self.read_lib_meas = []
|
self.read_lib_meas = []
|
||||||
self.clk_frmt = "clk{0}" # Unformatted clock name
|
self.clk_frmt = "clk{0}" # Unformatted clock name
|
||||||
targ_name = "{0}{1}_{2}".format(self.dout_name,"{}",self.probe_data) # Empty values are the port and probe data bit
|
targ_name = "{0}{1}_{2}".format(self.dout_name,"{}",self.probe_data) # Empty values are the port and probe data bit
|
||||||
|
|
@ -161,18 +160,18 @@ class delay(simulation):
|
||||||
def create_debug_measurement_objects(self):
|
def create_debug_measurement_objects(self):
|
||||||
"""Create debug measurement to help identify failures."""
|
"""Create debug measurement to help identify failures."""
|
||||||
|
|
||||||
self.debug_volt_meas = []
|
self.dout_volt_meas = []
|
||||||
for meas in self.delay_meas:
|
for meas in self.delay_meas:
|
||||||
# Output voltage measures
|
# Output voltage measures
|
||||||
self.debug_volt_meas.append(voltage_at_measure("v_{}".format(meas.name),
|
self.dout_volt_meas.append(voltage_at_measure("v_{}".format(meas.name),
|
||||||
meas.targ_name_no_port))
|
meas.targ_name_no_port))
|
||||||
self.debug_volt_meas[-1].meta_str = meas.meta_str
|
self.dout_volt_meas[-1].meta_str = meas.meta_str
|
||||||
|
|
||||||
self.sen_meas = delay_measure("delay_sen", self.clk_frmt, self.sen_name, "FALL", "RISE", measure_scale=1e9)
|
self.sen_meas = delay_measure("delay_sen", self.clk_frmt, self.sen_name, "FALL", "RISE", measure_scale=1e9)
|
||||||
self.sen_meas.meta_str = sram_op.READ_ZERO
|
self.sen_meas.meta_str = sram_op.READ_ZERO
|
||||||
self.sen_meas.meta_add_delay = True
|
self.sen_meas.meta_add_delay = True
|
||||||
|
|
||||||
return self.debug_volt_meas+[self.sen_meas]
|
return self.dout_volt_meas+[self.sen_meas]
|
||||||
|
|
||||||
def create_read_bit_measures(self):
|
def create_read_bit_measures(self):
|
||||||
""" Adds bit measurements for read0 and read1 cycles """
|
""" Adds bit measurements for read0 and read1 cycles """
|
||||||
|
|
@ -213,7 +212,7 @@ class delay(simulation):
|
||||||
(cell_name, cell_inst) = self.sram.get_cell_name(self.sram.name, bit_row, bit_col)
|
(cell_name, cell_inst) = self.sram.get_cell_name(self.sram.name, bit_row, bit_col)
|
||||||
storage_names = cell_inst.mod.get_storage_net_names()
|
storage_names = cell_inst.mod.get_storage_net_names()
|
||||||
debug.check(len(storage_names) == 2, ("Only inverting/non-inverting storage nodes"
|
debug.check(len(storage_names) == 2, ("Only inverting/non-inverting storage nodes"
|
||||||
"supported for characterization. Storage nets={}").format(storage_names))
|
"supported for characterization. Storage nets={}").format(storage_names))
|
||||||
q_name = cell_name+'.'+str(storage_names[0])
|
q_name = cell_name+'.'+str(storage_names[0])
|
||||||
qbar_name = cell_name+'.'+str(storage_names[1])
|
qbar_name = cell_name+'.'+str(storage_names[1])
|
||||||
|
|
||||||
|
|
@ -559,8 +558,10 @@ class delay(simulation):
|
||||||
|
|
||||||
meas_cycle = self.cycle_times[self.measure_cycles[port][volt_meas.meta_str]]
|
meas_cycle = self.cycle_times[self.measure_cycles[port][volt_meas.meta_str]]
|
||||||
|
|
||||||
# Measurement occurs at the end of the period -> current period start + period
|
# Measurement occurs slightly into the next period so we know that the value
|
||||||
at_time = meas_cycle+self.period
|
# "stuck" after the end of the period -> current period start + 1.25*period
|
||||||
|
at_time = meas_cycle+1.25*self.period
|
||||||
|
|
||||||
return (at_time, port)
|
return (at_time, port)
|
||||||
|
|
||||||
def get_volt_when_measure_variants(self, port, volt_meas):
|
def get_volt_when_measure_variants(self, port, volt_meas):
|
||||||
|
|
@ -732,6 +733,11 @@ class delay(simulation):
|
||||||
# Loop through all targeted ports and collect delays and powers.
|
# Loop through all targeted ports and collect delays and powers.
|
||||||
result = [{} for i in self.all_ports]
|
result = [{} for i in self.all_ports]
|
||||||
|
|
||||||
|
|
||||||
|
# First, check that the memory has the right values at the right times
|
||||||
|
if not self.check_bit_measures():
|
||||||
|
return(False,{})
|
||||||
|
|
||||||
for port in self.targ_write_ports:
|
for port in self.targ_write_ports:
|
||||||
debug.info(2, "Checking write values for port {}".format(port))
|
debug.info(2, "Checking write values for port {}".format(port))
|
||||||
write_port_dict = {}
|
write_port_dict = {}
|
||||||
|
|
@ -753,7 +759,6 @@ class delay(simulation):
|
||||||
if not self.check_sen_measure(port):
|
if not self.check_sen_measure(port):
|
||||||
return (False,{})
|
return (False,{})
|
||||||
success = self.check_read_debug_measures(port)
|
success = self.check_read_debug_measures(port)
|
||||||
success = success and self.check_bit_measures()
|
|
||||||
|
|
||||||
# Check timing for read ports. Power is only checked if it was read correctly
|
# Check timing for read ports. Power is only checked if it was read correctly
|
||||||
if not self.check_valid_delays(read_port_dict) or not success:
|
if not self.check_valid_delays(read_port_dict) or not success:
|
||||||
|
|
@ -762,7 +767,7 @@ class delay(simulation):
|
||||||
debug.error("Failed to Measure Read Port Values:\n\t\t{0}".format(read_port_dict),1)
|
debug.error("Failed to Measure Read Port Values:\n\t\t{0}".format(read_port_dict),1)
|
||||||
|
|
||||||
result[port].update(read_port_dict)
|
result[port].update(read_port_dict)
|
||||||
|
|
||||||
return (True,result)
|
return (True,result)
|
||||||
|
|
||||||
def check_sen_measure(self, port):
|
def check_sen_measure(self, port):
|
||||||
|
|
@ -782,7 +787,6 @@ class delay(simulation):
|
||||||
|
|
||||||
# Currently, only check if the opposite than intended value was read during
|
# Currently, only check if the opposite than intended value was read during
|
||||||
# the read cycles i.e. neither of these measurements should pass.
|
# the read cycles i.e. neither of these measurements should pass.
|
||||||
success = True
|
|
||||||
# FIXME: these checks need to be re-done to be more robust against possible errors
|
# FIXME: these checks need to be re-done to be more robust against possible errors
|
||||||
bl_vals = {}
|
bl_vals = {}
|
||||||
br_vals = {}
|
br_vals = {}
|
||||||
|
|
@ -794,29 +798,35 @@ class delay(simulation):
|
||||||
br_vals[meas.meta_str] = val
|
br_vals[meas.meta_str] = val
|
||||||
|
|
||||||
debug.info(2,"{}={}".format(meas.name,val))
|
debug.info(2,"{}={}".format(meas.name,val))
|
||||||
|
|
||||||
bl_check = False
|
for meas in self.dout_volt_meas:
|
||||||
for meas in self.debug_volt_meas:
|
|
||||||
val = meas.retrieve_measure(port=port)
|
val = meas.retrieve_measure(port=port)
|
||||||
debug.info(2,"{}={}".format(meas.name, val))
|
debug.info(2,"{}={}".format(meas.name, val))
|
||||||
if type(val) != float:
|
debug.check(type(val)==float, "Error retrieving numeric measurement: {0} {1}".format(meas.name,val))
|
||||||
continue
|
|
||||||
|
|
||||||
if meas.meta_str == sram_op.READ_ONE and val < self.vdd_voltage*0.1:
|
if meas.meta_str == sram_op.READ_ONE and val < self.vdd_voltage*0.1:
|
||||||
success = False
|
dout_success = False
|
||||||
debug.info(1, "Debug measurement failed. Value {}V was read on read 1 cycle.".format(val))
|
debug.info(1, "Debug measurement failed. Value {}V was read on read 1 cycle.".format(val))
|
||||||
bl_check = self.check_bitline_meas(bl_vals[sram_op.READ_ONE], br_vals[sram_op.READ_ONE])
|
bl_success = self.check_bitline_meas(bl_vals[sram_op.READ_ONE], br_vals[sram_op.READ_ONE])
|
||||||
elif meas.meta_str == sram_op.READ_ZERO and val > self.vdd_voltage*0.9:
|
elif meas.meta_str == sram_op.READ_ZERO and val > self.vdd_voltage*0.9:
|
||||||
success = False
|
dout_success = False
|
||||||
debug.info(1, "Debug measurement failed. Value {}V was read on read 0 cycle.".format(val))
|
debug.info(1, "Debug measurement failed. Value {}V was read on read 0 cycle.".format(val))
|
||||||
bl_check = self.check_bitline_meas(br_vals[sram_op.READ_ONE], bl_vals[sram_op.READ_ONE])
|
bl_success = self.check_bitline_meas(br_vals[sram_op.READ_ONE], bl_vals[sram_op.READ_ONE])
|
||||||
|
elif meas.meta_str == sram_op.READ_ONE and val > self.vdd_voltage*0.9:
|
||||||
|
dout_success = True
|
||||||
|
bl_success = True
|
||||||
|
elif meas.meta_str == sram_op.READ_ZERO and val < self.vdd_voltage*0.1:
|
||||||
|
dout_success = True
|
||||||
|
bl_success = True
|
||||||
|
else:
|
||||||
|
dout_success = False
|
||||||
|
bl_success = False
|
||||||
# If the bitlines have a correct value while the output does not then that is a
|
# If the bitlines have a correct value while the output does not then that is a
|
||||||
# sen error. FIXME: there are other checks that can be done to solidfy this conclusion.
|
# sen error. FIXME: there are other checks that can be done to solidfy this conclusion.
|
||||||
if bl_check:
|
if not dout_success and bl_success:
|
||||||
debug.error("Sense amp enable timing error. Increase the delay chain through the configuration file.",1)
|
debug.error("Sense amp enable timing error. Increase the delay chain through the configuration file.",1)
|
||||||
|
|
||||||
return success
|
return dout_success
|
||||||
|
|
||||||
|
|
||||||
def check_bit_measures(self):
|
def check_bit_measures(self):
|
||||||
|
|
@ -824,7 +834,6 @@ class delay(simulation):
|
||||||
Checks the measurements which represent the internal storage voltages
|
Checks the measurements which represent the internal storage voltages
|
||||||
at the end of the read cycle.
|
at the end of the read cycle.
|
||||||
"""
|
"""
|
||||||
success = True
|
|
||||||
for polarity, meas_list in self.bit_meas.items():
|
for polarity, meas_list in self.bit_meas.items():
|
||||||
for meas in meas_list:
|
for meas in meas_list:
|
||||||
val = meas.retrieve_measure()
|
val = meas.retrieve_measure()
|
||||||
|
|
@ -839,10 +848,18 @@ class delay(simulation):
|
||||||
elif (meas_cycle == sram_op.READ_ZERO and polarity == bit_polarity.INVERTING) or\
|
elif (meas_cycle == sram_op.READ_ZERO and polarity == bit_polarity.INVERTING) or\
|
||||||
(meas_cycle == sram_op.READ_ONE and polarity == bit_polarity.NONINVERTING):
|
(meas_cycle == sram_op.READ_ONE and polarity == bit_polarity.NONINVERTING):
|
||||||
success = val > self.vdd_voltage/2
|
success = val > self.vdd_voltage/2
|
||||||
|
elif (meas_cycle == sram_op.WRITE_ZERO and polarity == bit_polarity.INVERTING) or\
|
||||||
|
(meas_cycle == sram_op.WRITE_ONE and polarity == bit_polarity.NONINVERTING):
|
||||||
|
success = val > self.vdd_voltage/2
|
||||||
|
elif (meas_cycle == sram_op.WRITE_ONE and polarity == bit_polarity.INVERTING) or\
|
||||||
|
(meas_cycle == sram_op.WRITE_ZERO and polarity == bit_polarity.NONINVERTING):
|
||||||
|
success = val < self.vdd_voltage/2
|
||||||
|
else:
|
||||||
|
success = False
|
||||||
if not success:
|
if not success:
|
||||||
debug.info(1,("Wrong value detected on probe bit during read cycle. "
|
debug.info(1,("Wrong value detected on probe bit during read/write cycle. "
|
||||||
"Check writes and control logic for bugs.\n measure={}, op={}, "
|
"Check writes and control logic for bugs.\n measure={}, op={}, "
|
||||||
"bit_storage={}, V(bit)={}").format(meas.name, meas_cycle.name, polarity.name,val))
|
"bit_storage={}, V(bit)={}").format(meas.name, meas_cycle.name, polarity.name,val))
|
||||||
return success
|
return success
|
||||||
|
|
||||||
def check_bitline_meas(self, v_discharged_bl, v_charged_bl):
|
def check_bitline_meas(self, v_discharged_bl, v_charged_bl):
|
||||||
|
|
|
||||||
|
|
@ -404,7 +404,7 @@ class bank(design.design):
|
||||||
def create_bitcell_array(self):
|
def create_bitcell_array(self):
|
||||||
""" Creating Bitcell Array """
|
""" Creating Bitcell Array """
|
||||||
|
|
||||||
self.bitcell_array_inst=self.add_inst(name="bitcell_array",
|
self.bitcell_array_inst=self.add_inst(name="replica_bitcell_array",
|
||||||
mod=self.bitcell_array)
|
mod=self.bitcell_array)
|
||||||
|
|
||||||
temp = []
|
temp = []
|
||||||
|
|
|
||||||
|
|
@ -53,13 +53,13 @@ class replica_column(design.design):
|
||||||
self.DRC_LVS()
|
self.DRC_LVS()
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
column_list = self.cell.get_all_bitline_names()
|
|
||||||
for cell_column in column_list:
|
for bl_name in self.cell.get_all_bitline_names():
|
||||||
self.add_pin("{0}_{1}".format(cell_column,0))
|
self.add_pin("{0}_{1}".format(bl_name,0))
|
||||||
row_list = self.cell.get_all_wl_names()
|
|
||||||
for row in range(self.total_size):
|
for row in range(self.total_size):
|
||||||
for cell_row in row_list:
|
for wl_name in self.cell.get_all_wl_names():
|
||||||
self.add_pin("{0}_{1}".format(cell_row,row))
|
self.add_pin("{0}_{1}".format(wl_name,row))
|
||||||
|
|
||||||
self.add_pin("vdd")
|
self.add_pin("vdd")
|
||||||
self.add_pin("gnd")
|
self.add_pin("gnd")
|
||||||
|
|
@ -112,21 +112,18 @@ class replica_column(design.design):
|
||||||
def add_layout_pins(self):
|
def add_layout_pins(self):
|
||||||
""" Add the layout pins """
|
""" Add the layout pins """
|
||||||
|
|
||||||
row_list = self.cell.get_all_wl_names()
|
for bl_name in self.cell.get_all_bitline_names():
|
||||||
column_list = self.cell.get_all_bitline_names()
|
bl_pin = self.cell_inst[0].get_pin(bl_name)
|
||||||
|
self.add_layout_pin(text=bl_name,
|
||||||
for cell_column in column_list:
|
|
||||||
bl_pin = self.cell_inst[0].get_pin(cell_column)
|
|
||||||
self.add_layout_pin(text=cell_column,
|
|
||||||
layer="metal2",
|
layer="metal2",
|
||||||
offset=bl_pin.ll(),
|
offset=bl_pin.ll(),
|
||||||
width=bl_pin.width(),
|
width=bl_pin.width(),
|
||||||
height=self.height)
|
height=self.height)
|
||||||
|
|
||||||
for row in range(self.total_size):
|
for row in range(self.total_size):
|
||||||
for cell_row in row_list:
|
for wl_name in self.cell.get_all_wl_names():
|
||||||
wl_pin = self.cell_inst[row].get_pin(cell_row)
|
wl_pin = self.cell_inst[row].get_pin(wl_name)
|
||||||
self.add_layout_pin(text=cell_row+"_{0}".format(row),
|
self.add_layout_pin(text="{0}_{1}".format(wl_name,row),
|
||||||
layer="metal1",
|
layer="metal1",
|
||||||
offset=wl_pin.ll().scale(0,1),
|
offset=wl_pin.ll().scale(0,1),
|
||||||
width=self.width,
|
width=self.width,
|
||||||
|
|
@ -159,4 +156,4 @@ class replica_column(design.design):
|
||||||
for row, cell in self.cell_inst.items():
|
for row, cell in self.cell_inst.items():
|
||||||
if row == selected_row:
|
if row == selected_row:
|
||||||
continue
|
continue
|
||||||
self.graph_inst_exclude.add(cell)
|
self.graph_inst_exclude.add(cell)
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,7 @@ class sram_factory:
|
||||||
|
|
||||||
# Use the default name if there are default arguments
|
# Use the default name if there are default arguments
|
||||||
# This is especially for library cells so that the spice and gds files can be found.
|
# This is especially for library cells so that the spice and gds files can be found.
|
||||||
|
print(module_type,len(kwargs))
|
||||||
if len(kwargs)>0:
|
if len(kwargs)>0:
|
||||||
# Create a unique name and increment the index
|
# Create a unique name and increment the index
|
||||||
module_name = "{0}_{1}".format(module_type, self.module_indices[module_type])
|
module_name = "{0}_{1}".format(module_type, self.module_indices[module_type])
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue