def lookup_table_to_conditional_expression(lookup_table, input_variables): conditional_expression = [] for input_values, output_value in lookup_table.items(): if len(input_values) == 1: conditional = z3p.Eq(input_variables[0], input_values[0]) elif len(input_values) == 0: assert len(lookup_table.values()) == 1 return [(z3p.BoolVal(True), output_value)] else: conditional = z3p.And([ z3p.Eq(var, val) for var, val in zip(input_variables, input_values) ]) conditional_expression += [(conditional, output_value)] return conditional_expression
def condition_to_resolve_deadlock(self, locations, memory, verbose=1): """Locations is a map from automaton to current location Memory can contain symbolic values. """ if verbose > 0: print "Deadlock locations {}".format(locations) candidates = self.candidate_transitions(locations) if verbose > 0: print "Candidates are {}".format(candidates) if len(candidates) == 0: return z3p.BoolVal(False) else: return z3p.Or([z3p.And([a.transition_condition(edge[2]['name'], memory[a]) for a, edge in candidate]) for candidate in candidates])
def evaluate_expression(expression, symbolic_memory, concrete_memory, tables=None): if isinstance(expression, int): return expression if isinstance(expression, tuple): return expression if z3p.is_const(expression): if z3p.is_bool_or_int_value(expression): return expression if expression in symbolic_memory: return symbolic_memory[expression] elif expression.decl().name().startswith('table_'): assert expression.decl().name() in tables table_expression = tables[expression.decl().name()] first_value = table_expression[0][1] if first_value.sort() == z3p.IntSort(): last_else = z3p.IntVal(0) else: last_else = z3p.BoolVal(False) if_expression = None for conditional, value in table_expression: guard = evaluate_expression(conditional, symbolic_memory, concrete_memory) last_else = z3p.If(guard, value, last_else) return z3p.simplify(last_else) else: return concrete_memory[expression] elif expression.decl().kind() == z3p.Z3_OP_SELECT: if expression in symbolic_memory: return symbolic_memory[expression] else: return concrete_memory[expression] else: new_args = [ evaluate_expression(expression.arg(i), symbolic_memory, concrete_memory, tables) for i in range(expression.num_args()) ] if expression.decl().kind() == z3p.Z3_OP_AND: return z3p.And(*new_args) else: return expression.decl()(*new_args)
def create_update_hole(self, variable_or_variable_name, hole_name): """ variable is the name of the variable to update """ if isinstance(variable_or_variable_name, str): variable_to_update = next(v for v in self.variables if v.decl().name() == variable_or_variable_name) else: variable_to_update = variable_or_variable_name signature = [] domains = [] for variable in self.variables: variable_sort = variable.sort() signature.append(variable_sort) if variable.sort() == z3p.IntSort(): domains.append([z3p.IntVal(i) for i in range(self.variable_ranges[variable][0], self.variable_ranges[variable][1] + 1)]) elif variable.sort() == z3p.BoolSort(): domains.append([z3p.BoolVal(False), z3p.BoolVal(True)]) else: raise NotImplementedError("Unimplemented type of variable {}".format(variable_sort)) signature.append(variable_to_update.sort()) f = z3p.Function(hole_name, *signature) constraint = z3p.And([z3p.Or([z3p.Eq(f(*arg), z3p.IntVal(result)) for result in range(self.variable_ranges[variable_to_update][0], self.variable_ranges[variable_to_update][1] + 1)]) for arg in itertools.product(*domains)]) return (f, domains, constraint, (variable_to_update, self.variables.index(variable_to_update)))
def directory(d, num_caches=2, num_values=1, num_addresses=1): transitions = [] variables = [] variable_ranges = {} DataBlk = z3p.Int('DataBlk') ActiveId = z3p.Int('ActiveId') Sharers = {} for cache_id in range(num_caches): Sharers[cache_id] = z3p.Int('Sharers_{}'.format(cache_id)) NumSharers = z3p.Int('NumSharers') Owner = z3p.Int('Owner') variable_ranges = {DataBlk: (0, num_values - 1), ActiveId: (0, num_caches - 1), NumSharers: (0, num_caches), Owner: (0, num_caches - 1)} for cache_id in range(num_caches): variable_ranges[Sharers[cache_id]] = (0, 1) # Do i need numsharers variables = [DataBlk, ActiveId, NumSharers, Owner] + [Sharers[cache_id] for cache_id in range(num_caches)] initial_values = [ZERO, ZERO, ZERO, ZERO] + num_caches * [ZERO] locations = ['D_I', 'D_S', 'D_M', 'D_BUSY', 'D_DATA', 'D_PENDING_UNBLOCK_E', 'D_BUSY_DATA'] # input messages input_channels = [] for c in range(num_caches): for a in range(num_addresses): input_channels.extend([GetXMsgP[c][d][a], GetSMsgP[c][d][a], WBMsgP[c][d][a], UnblockSMsgP[c][d][a], UnblockEMsgP[c][d][a]]) for other_c in range(num_caches): if other_c != c: input_channels.append(DataMsgC2CP[c][other_c][d][a]) output_channels = [] # output messages for c in range(num_caches): for a in range(num_addresses): output_channels.extend([FwdGetXMsg[c][d][a], FwdGetSMsg[c][d][a], DataMsgD2C[c][d][a], WBAckMsg[c][d][a]]) for c in range(num_caches): for a in range(num_addresses): # // Transitions from I # D_I on GetXMsg'[c][d][a] { ActiveId := c; } -> # send DataMsgD2C[c][d][a] (DataBlk, 0) -> D_BUSY; target = 'D_I2_{}'.format(c) transitions.append((None, 'D_I', GetXMsgP[c][d][a], TRUE, [(ActiveId, INT(c))], target)) transitions.append((None, target, DataMsgD2C[c][d][a], [DataBlk, ZERO], TRUE, [], 'D_BUSY')) locations.append(target) # D_I on GetSMsg'[c][d][a] { ActiveId := c; } -> # send DataMsgD2C[c][d][a] (DataBlk, 0) -> D_BUSY; target = 'D_I3_{}'.format(c) transitions.append((None, 'D_I', GetSMsgP[c][d][a], TRUE, [(ActiveId, INT(c))], target)) transitions.append((None, target, DataMsgD2C[c][d][a], [DataBlk, ZERO], TRUE, [], 'D_BUSY')) locations.append(target) # // Transitions from S # D_S on GetXMsg'[c][d][a] { ActiveId := c; } -> # send DataMsgD2C[c][d][a] (DataBlk, NumSharers) {} -> # foreach c2 in CacheIDType { # if (Sharers[c2]) send FwdGetXMsg[c2][d][a] (c) {}; # if (not Sharers[c2]) pass {}; # } -> D_BUSY; target = 'D_S2_{}'.format(c) target2 = 'D_S3_{}'.format(c) transitions.append((None, 'D_S', GetXMsgP[c][d][a], TRUE, [(ActiveId, INT(c))], target)) transitions.append((None, target, DataMsgD2C[c][d][a], [DataBlk, NumSharers - 1], z3p.Eq(Sharers[c], ONE), [], target2)) transitions.append((None, target, DataMsgD2C[c][d][a], [DataBlk, NumSharers], z3p.Eq(Sharers[c], ZERO), [], target2)) locations.extend([target, target2]) last_state = 'D_S3_{}'.format(c) other_caches = [other_c for other_c in range(num_caches) if c != other_c] for i, other_c in enumerate(other_caches): if other_c != c: if i + 1 == len(other_caches): target = 'D_BUSY' else: target = 'D_S3_{}_{}'.format(c, other_c) source = last_state transitions.append((None, source, FwdGetXMsg[other_c][d][a], [z3p.IntVal(c)], z3p.Eq(Sharers[other_c], ONE), [], target)) transitions.append((None, source, z3p.Neq(Sharers[other_c], ONE), [], target)) locations.extend([target]) last_state = target # D_S on GetSMsg'[c][d][a] { ActiveId := c; } -> # send DataMsgD2C[c][d][a] (DataBlk, 0) {} -> D_BUSY; target = 'D_S4_{}'.format(c) transitions.append((None, 'D_S', GetSMsgP[c][d][a], TRUE, [(ActiveId, INT(c))], target)) transitions.append((None, target, DataMsgD2C[c][d][a], [DataBlk, ZERO], TRUE, [], 'D_BUSY')) locations.append(target) # // Transitions from M # D_M on GetXMsg'[c][d][a] { ActiveId := c; } -> # send FwdGetXMsg[Owner][d][a] (ActiveId) {} -> D_BUSY; target = 'D_M2_{}'.format(c) transitions.append((None, 'D_M', GetXMsgP[c][d][a], TRUE, [(ActiveId, INT(c))], target)) for c2 in range(num_caches): transitions.append((None, target, FwdGetXMsg[c2][d][a], [ActiveId], z3p.Eq(INT(c2), Owner), [], 'D_BUSY')) locations.append(target) # D_M on GetSMsg'[c][d][a] { ActiveId := c; } -> # send FwdGetSMsg[Owner][d][a] (ActiveId) {} -> D_BUSY_DATA; target = 'D_M3_{}'.format(c) transitions.append((None, 'D_M', GetSMsgP[c][d][a], TRUE, [(ActiveId, INT(c))], target)) for c2 in range(num_caches): transitions.append((None, target, FwdGetSMsg[c2][d][a], [ActiveId], z3p.Eq(INT(c2), Owner), [], 'D_BUSY_DATA')) locations.append(target) # D_M on WBMsg'[c][d][a] (v) { DataBlk := v; Sharers[c] := false; } -> # send WBAckMsg[c][d][a] {} -> D_I; target = 'D_M4_{}'.format(c) transitions.append((None, 'D_M', WBMsgP[c][d][a], z3p.Eq(Sharers[c], ONE), [(DataBlk, WBMsgP[c][d][a]), (Sharers[c], ZERO), (NumSharers, NumSharers - 1)], target)) # debug transitions.append((None, 'D_M', WBMsgP[c][d][a], z3p.Neq(Sharers[c], ONE), [(DataBlk, WBMsgP[c][d][a])], target)) transitions.append((None, target, WBAckMsg[c][d][a], [ZERO], TRUE, [(ActiveId, ZERO)], 'D_I')) locations.append(target) # // Transitions from BUSY # D_BUSY on WBMsg'[c][d][a] (v) # if (= c ActiveId) { DataBlk := v; } -> D_PENDING_UNBLOCK_E; # if (!= c ActiveId) { Sharers[c] := false; DataBlk := v; } -> # send DataMsgD2C[ActiveId][d][a] (DataBlk, 0) -> D_BUSY; transitions.append((None, 'D_BUSY', WBMsgP[c][d][a], z3p.Eq(INT(c), ActiveId), [(DataBlk, WBMsgP[c][d][a])], 'D_PENDING_UNBLOCK_E')) target = 'D_BUSY2_{}'.format(c) transitions.append((None, 'D_BUSY', WBMsgP[c][d][a], z3p.And(z3p.Neq(INT(c), ActiveId), z3p.Eq(Sharers[c], ONE)), [(Sharers[c], ZERO), (NumSharers, NumSharers - 1), (DataBlk, WBMsgP[c][d][a])], target)) # debug transitions.append((None, 'D_BUSY', WBMsgP[c][d][a], z3p.And(z3p.Neq(INT(c), ActiveId), z3p.Eq(Sharers[c], ZERO)), [(DataBlk, WBMsgP[c][d][a])], target)) for c2 in range(num_caches): transitions.append((None, target, DataMsgD2C[c2][d][a], [DataBlk, ONE], z3p.Eq(INT(c2), ActiveId), [], 'D_BUSY')) locations.append(target) # D_BUSY on UnblockEMsg'[c][d][a] { Sharers[c] := true; Owner := c; } -> D_M; transitions.append((None, 'D_BUSY', UnblockEMsgP[c][d][a], TRUE, [(Sharers[c], ONE), (NumSharers, ONE), (Owner, INT(c)), (ActiveId, ZERO)] + [(Sharers[other_c], ZERO) for other_c in range(num_caches) if other_c != c], 'D_M')) # D_BUSY on UnblockSMsg'[c][d][a] { Sharers[c] := true; Owner := undef; } -> D_S; transitions.append((None, 'D_BUSY', UnblockSMsgP[c][d][a], z3p.Eq(Sharers[c], ZERO), [(Sharers[c], ONE), (NumSharers, NumSharers + 1), (Owner, ZERO), (ActiveId, ZERO)], 'D_S')) # debug transitions.append((None, 'D_BUSY', UnblockSMsgP[c][d][a], z3p.Eq(Sharers[c], ONE), [(Owner, ZERO), (ActiveId, ZERO)], 'D_S')) # foreach c2 in CacheIDType (!= c2 c) { # D_BUSY on DataMsgC2C'[c2][c][d][a] (v) { DataBlk := v; } -> S; # } for c2 in range(num_caches): if c2 != c: transitions.append((None, 'D_BUSY', DataMsgC2CP[c2][c][d][a], TRUE, [(DataBlk, DataMsgC2CP[c2][c][d][a]), (ActiveId, ZERO)], 'D_S')) # // Transitions from BUSY_DATA # D_BUSY_DATA on UnblockSMsg'[c][d][a] { Sharers[c] := true; } -> D_BUSY; # foreach c2 in CacheIDType (!= c2 c) { # D_BUSY_DATA on DataMsgC2C'[c2][c][d][a] (v) { DataBlk := v; } -> D_BUSY; # } transitions.append((None, 'D_BUSY_DATA', UnblockSMsgP[c][d][a], z3p.Eq(Sharers[c], ZERO), [(Sharers[c], ONE), (NumSharers, NumSharers + 1)], 'D_BUSY')) # debug transitions.append((None, 'D_BUSY_DATA', UnblockSMsgP[c][d][a], z3p.Eq(Sharers[c], ONE), [], 'D_BUSY')) for c2 in range(num_caches): if c2 != c: transitions.append((None, 'D_BUSY_DATA', DataMsgC2CP[c2][c][d][a], TRUE, [(DataBlk, DataMsgC2CP[c2][c][d][a])], 'D_BUSY')) # D_BUSY_DATA on WBMsg'[c][d][a] (v) # if (= c ActiveId) { DataBlk := v; } -> D_PENDING_UNBLOCK_E; # if (!= c ActiveId) { Sharers[c] := false; DataBlk := v; } -> # send DataMsgD2C[ActiveId][d][a] (DataBlk, 0) -> D_BUSY; transitions.append((None, 'D_BUSY_DATA', WBMsgP[c][d][a], z3p.Eq(z3p.IntVal(c), ActiveId), [(DataBlk, WBMsgP[c][d][a])], 'D_PENDING_UNBLOCK_E')) target = 'D_BUSY2_{}'.format(c) transitions.append((None, 'D_BUSY_DATA', WBMsgP[c][d][a], z3p.And(z3p.Neq(z3p.IntVal(c), ActiveId), z3p.Eq(Sharers[c], ONE)), [(Sharers[c], ZERO), (NumSharers, NumSharers - 1), (DataBlk, WBMsgP[c][d][a])], target)) # debug transitions.append((None, 'D_BUSY_DATA', WBMsgP[c][d][a], z3p.And(z3p.Neq(z3p.IntVal(c), ActiveId), z3p.Eq(Sharers[c], ZERO)), [(DataBlk, WBMsgP[c][d][a])], target)) # for c2 in range(num_caches): # transitions.append((None, 'D_BUSY_DATA2', DataMsgD2C[c2][a], [DataBlk, ZERO], z3p.Eq(z3p.IntVal(c2), ActiveId), [], 'D_BUSY')) # // Transitions from PENDING_UNBLOCK_E # D_PENDING_UNBLOCK_E on UnblockEMsg'[c][d][a] { Sharers[c] := false; Owner := undef; } -> D_I; target = 'D_PENDING_UNBLOCK_E_{}'.format(c) transitions.append((None, 'D_PENDING_UNBLOCK_E', UnblockEMsgP[c][d][a], z3p.Eq(Sharers[c], ONE), [(Sharers[c], ZERO), (Owner, ZERO), (NumSharers, NumSharers - 1)], target)) #debug transitions.append((None, 'D_PENDING_UNBLOCK_E', UnblockEMsgP[c][d][a], z3p.Eq(Sharers[c], ZERO), [], target)) transitions.append((None, target, WBAckMsg[c][d][a], [ZERO], TRUE, [], 'D_I')) locations.append(target) return automaton.SymbolicAutomaton('directory', locations, 'D_I', transitions, variables=variables, initial_values=initial_values, input_channels=input_channels, output_channels=output_channels, variable_ranges=variable_ranges)
def lossless_non_duplicating_blocking_unordered_channel( name, inputs, outputs, data_ranges, port_number_of_fields, capacity): variables = [] initial_values = [] variable_ranges = {} counters = [] print inputs print outputs for input in inputs: input_name = input.decl().name() input_counter = z3p.Int(input_name + '_counter') variables.append(input_counter) initial_values.append(ZERO) variable_ranges[input_counter] = (0, capacity) counters.append(input_counter) # if the type of the port is unit then all we need is the counter if not isinstance(input, z3p.ArrayRef): if input in data_ranges: for i in range(capacity): variable = z3p.Int('{}_cell{}'.format( input.decl().name(), i)) variables.append(variable) initial_values.append(ZERO) variable_ranges[variable] = data_ranges[input] else: for i in range(capacity): for j in range(port_number_of_fields[input]): variable = z3p.Int('{}_field_{}_cell{}'.format( input.decl().name(), j, i)) variables.append(variable) initial_values.append(ZERO) variable_ranges[variable] = data_ranges[input[j]] locations = ['initial'] transitions = [] for input, output in zip(inputs, outputs): input_name = input.decl().name() output_name = output.decl().name() input_counter = z3p.Int(input_name + '_counter') for i in range(capacity): updates = [] if not isinstance(input, z3p.ArrayRef): if input in data_ranges: variable = z3p.Int('{}_cell{}'.format( input.decl().name(), i)) updates.append((variable, input)) else: for j in range(port_number_of_fields[input]): variable = z3p.Int('{}_field_{}_cell{}'.format( input.decl().name(), j, i)) updates.append((variable, input[j])) last = counters[0] for counter in counters[1:]: last = z3p.Sum(last, counter) counters_sum = last transitions.append( ('t_{}'.format(input_name), 'initial', input, z3p.And(counters_sum < z3p.IntVal(capacity), z3p.Eq(input_counter, i)), [(input_counter, input_counter + 1)] + updates, 'initial')) if i > 0: updates = [] channel_outputs = [] if not isinstance(input, z3p.ArrayRef): if input in data_ranges: variable = z3p.Int('{}_cell{}'.format( input.decl().name(), i)) channel_outputs.append(variable) updates.append((variable, ZERO)) else: channel_outputs.append(ZERO) else: for j in range(port_number_of_fields[input]): variable = z3p.Int('{}_field_{}_cell{}'.format( input.decl().name(), j, i)) channel_outputs.append(variable) updates.append((variable, ZERO)) transitions.append( ('t_{}'.format(output_name), 'initial', output, channel_outputs, z3p.Eq(input_counter, z3p.IntVal(i)), [(input_counter, input_counter - 1)] + updates, 'initial')) return automaton.SymbolicAutomaton('{}_channel'.format(name), locations, 'initial', transitions, variables=variables, initial_values=initial_values, input_channels=inputs, output_channels=outputs, variable_ranges=variable_ranges)