From fb60b51c7268ee1ddc8729a35deed950c38fa9b2 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 24 Jul 2019 16:57:04 -0700 Subject: [PATCH] Add check bits. Clean up logic. Move read/write bit check to next cycle. --- compiler/characterizer/delay.py | 71 ++++++++++++++++++------------ compiler/modules/bank.py | 2 +- compiler/modules/replica_column.py | 29 ++++++------ compiler/sram_factory.py | 1 + 4 files changed, 59 insertions(+), 44 deletions(-) diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index 1274fafc..921b73b9 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -82,7 +82,6 @@ class delay(simulation): def create_read_port_measurement_objects(self): """Create the measurements used for read ports: delays, slews, powers""" - import pdb; pdb.set_trace() self.read_lib_meas = [] 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 @@ -161,18 +160,18 @@ class delay(simulation): def create_debug_measurement_objects(self): """Create debug measurement to help identify failures.""" - self.debug_volt_meas = [] + self.dout_volt_meas = [] for meas in self.delay_meas: # 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)) - 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.meta_str = sram_op.READ_ZERO 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): """ 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) storage_names = cell_inst.mod.get_storage_net_names() 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]) 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]] - # Measurement occurs at the end of the period -> current period start + period - at_time = meas_cycle+self.period + # Measurement occurs slightly into the next period so we know that the value + # "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) 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. 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: debug.info(2, "Checking write values for port {}".format(port)) write_port_dict = {} @@ -753,7 +759,6 @@ class delay(simulation): if not self.check_sen_measure(port): return (False,{}) 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 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) result[port].update(read_port_dict) - + return (True,result) 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 # 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 bl_vals = {} br_vals = {} @@ -794,29 +798,35 @@ class delay(simulation): br_vals[meas.meta_str] = val debug.info(2,"{}={}".format(meas.name,val)) - - bl_check = False - for meas in self.debug_volt_meas: + + for meas in self.dout_volt_meas: val = meas.retrieve_measure(port=port) debug.info(2,"{}={}".format(meas.name, val)) - if type(val) != float: - continue + debug.check(type(val)==float, "Error retrieving numeric measurement: {0} {1}".format(meas.name,val)) 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)) - 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: - success = False + dout_success = False 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 # 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) - return success + return dout_success def check_bit_measures(self): @@ -824,7 +834,6 @@ class delay(simulation): Checks the measurements which represent the internal storage voltages at the end of the read cycle. """ - success = True for polarity, meas_list in self.bit_meas.items(): for meas in meas_list: val = meas.retrieve_measure() @@ -839,10 +848,18 @@ class delay(simulation): elif (meas_cycle == sram_op.READ_ZERO and polarity == bit_polarity.INVERTING) or\ (meas_cycle == sram_op.READ_ONE and polarity == bit_polarity.NONINVERTING): 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: - debug.info(1,("Wrong value detected on probe bit during read cycle. " - "Check writes and control logic for bugs.\n measure={}, op={}, " - "bit_storage={}, V(bit)={}").format(meas.name, meas_cycle.name, polarity.name,val)) + debug.info(1,("Wrong value detected on probe bit during read/write cycle. " + "Check writes and control logic for bugs.\n measure={}, op={}, " + "bit_storage={}, V(bit)={}").format(meas.name, meas_cycle.name, polarity.name,val)) return success def check_bitline_meas(self, v_discharged_bl, v_charged_bl): diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 11e5adca..2f467961 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -404,7 +404,7 @@ class bank(design.design): def create_bitcell_array(self): """ 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) temp = [] diff --git a/compiler/modules/replica_column.py b/compiler/modules/replica_column.py index fdd726f5..b18c49fe 100644 --- a/compiler/modules/replica_column.py +++ b/compiler/modules/replica_column.py @@ -53,13 +53,13 @@ class replica_column(design.design): self.DRC_LVS() def add_pins(self): - column_list = self.cell.get_all_bitline_names() - for cell_column in column_list: - self.add_pin("{0}_{1}".format(cell_column,0)) - row_list = self.cell.get_all_wl_names() + + for bl_name in self.cell.get_all_bitline_names(): + self.add_pin("{0}_{1}".format(bl_name,0)) + for row in range(self.total_size): - for cell_row in row_list: - self.add_pin("{0}_{1}".format(cell_row,row)) + for wl_name in self.cell.get_all_wl_names(): + self.add_pin("{0}_{1}".format(wl_name,row)) self.add_pin("vdd") self.add_pin("gnd") @@ -112,21 +112,18 @@ class replica_column(design.design): def add_layout_pins(self): """ Add the layout pins """ - row_list = self.cell.get_all_wl_names() - column_list = self.cell.get_all_bitline_names() - - for cell_column in column_list: - bl_pin = self.cell_inst[0].get_pin(cell_column) - self.add_layout_pin(text=cell_column, + for bl_name in self.cell.get_all_bitline_names(): + bl_pin = self.cell_inst[0].get_pin(bl_name) + self.add_layout_pin(text=bl_name, layer="metal2", offset=bl_pin.ll(), width=bl_pin.width(), height=self.height) for row in range(self.total_size): - for cell_row in row_list: - wl_pin = self.cell_inst[row].get_pin(cell_row) - self.add_layout_pin(text=cell_row+"_{0}".format(row), + for wl_name in self.cell.get_all_wl_names(): + wl_pin = self.cell_inst[row].get_pin(wl_name) + self.add_layout_pin(text="{0}_{1}".format(wl_name,row), layer="metal1", offset=wl_pin.ll().scale(0,1), width=self.width, @@ -159,4 +156,4 @@ class replica_column(design.design): for row, cell in self.cell_inst.items(): if row == selected_row: continue - self.graph_inst_exclude.add(cell) \ No newline at end of file + self.graph_inst_exclude.add(cell) diff --git a/compiler/sram_factory.py b/compiler/sram_factory.py index 0083841d..b5e46646 100644 --- a/compiler/sram_factory.py +++ b/compiler/sram_factory.py @@ -70,6 +70,7 @@ class sram_factory: # 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. + print(module_type,len(kwargs)) if len(kwargs)>0: # Create a unique name and increment the index module_name = "{0}_{1}".format(module_type, self.module_indices[module_type])