def lookup_table_for_inputs_to_negative_constraint(self, function_name, input_values_set): """Translate look-up table to negative constraint for specific inputs. """ lookup_table = self.lookup_table_for_function(function_name) constraint = lambda f: z3p.Or([ z3p.Neq(f(*input_values), output_value) for input_values, output_value in lookup_table.items() if set(input_values) in input_values_set ]) return constraint
def lookup_table_to_negative_constraint(self, function_name): """Translate look-up table to negative constraint. Given input variables as z3 variables, translate look-up table to a constraint that guarantees that the same look-up table will not be a solution. """ lookup_table = self.lookup_table_for_function(function_name) constraint = lambda f: z3p.Or([ z3p.Neq(f(*input_values), output_value) for input_values, output_value in lookup_table.items() ]) return constraint
def receiver(): forward_output_channel = z3p.Array('forward_output_channel', z3p.IntSort(), z3p.IntSort()) backward_input_channel = z3p.Int('backward_input_channel') receive = z3p.Int('receive') input_tag = z3p.Int('receiver_tag') input_data = z3p.Int('receiver_data') expected_tag = z3p.Int('expected_tag') transitions = [] transitions.append( ('t0', 'initial', forward_output_channel, z3p.BoolVal(True), [(input_tag, forward_output_channel[0]), (input_data, forward_output_channel[1])], 'q0')) transitions.append( ('t1', 'q0', receive, [input_data], z3p.Eq(input_tag, expected_tag), [], 'q1')) transitions.append( ('t2', 'q1', backward_input_channel, [expected_tag], z3p.BoolVal(True), [(expected_tag, z3p.If(z3p.Eq(expected_tag, 0), z3p.IntVal(1), z3p.IntVal(0)))], 'initial')) transitions.append(('t3', 'q0', z3p.Neq(input_tag, expected_tag), [], 'q2')) transitions.append( ('t4', 'q2', backward_input_channel, [z3p.If(z3p.Eq(expected_tag, 0), z3p.IntVal(1), z3p.IntVal(0))], z3p.BoolVal(True), [], 'initial')) return automaton.SymbolicAutomaton( 'receiver', ['initial', 'q0', 'q1', 'q2'], 'initial', transitions, input_channels=[forward_output_channel], output_channels=[receive, backward_input_channel], variables=[input_tag, input_data, expected_tag], initial_values=[z3p.IntVal(0), z3p.IntVal(0), z3p.IntVal(0)], variable_ranges={ input_tag: (0, 1), input_data: (min_value_message, max_value_message), expected_tag: (0, 1) }, output_channel_ranges={ receive: (min_value_message, max_value_message), backward_input_channel: (0, 1) }, justice=['t3', 't1'])
def guard_enabled(self, state, guard, verbose=0): if guard.decl().name().startswith('table'): conditional = self.tables[guard.decl().name()] expression = z3p.BoolVal(False) for condition, result in conditional: expression = z3p.Or(expression, condition if z3p.is_true(result) else z3p.BoolVal(False)) guard = expression guard_evaluated = util.evaluate_expression(guard, {}, state, self.tables) if verbose > 0: print 'Evaluated guard is {}'.format(guard_evaluated) print 'Simplified guard is {}'.format(z3p.simplify(guard_evaluated)) s = z3p.Solver() s.add(z3p.Neq(guard_evaluated, True)) if s.check() == z3p.unsat: return True else: return False
def sender(): transitions = [] input_message = z3p.Int('sender_input_message') sender_tag = z3p.Int('sender_tag') ack_tag = z3p.Int('ack_tag') forward_input_channel = z3p.Array('forward_input_channel', z3p.IntSort(), z3p.IntSort()) backward_output_channel = z3p.Int('backward_output_channel') send = z3p.Int('send') timeout = util.new_variable('timeout', 'unit') transitions.append(('t0', 'initial', send, z3p.BoolVal(True), [(input_message, send)], 'q0')) transitions.append( ('t1', 'q0', forward_input_channel, [sender_tag, input_message], z3p.BoolVal(True), [], 'q1')) transitions.append(('t2', 'q1', timeout, z3p.BoolVal(True), [], 'q0')) transitions.append(('t3', 'q1', backward_output_channel, z3p.BoolVal(True), [(ack_tag, backward_output_channel)], 'q2')) transitions.append(('t4', 'q2', z3p.Eq(ack_tag, sender_tag), [ (sender_tag, z3p.If(z3p.Eq(sender_tag, 0), z3p.IntVal(1), z3p.IntVal(0))) ], 'initial')) transitions.append(('t5', 'q2', z3p.Neq(ack_tag, sender_tag), [], 'q0')) return automaton.SymbolicAutomaton( 'sender', ['initial', 'q0', 'q1', 'q2'], 'initial', transitions, variables=[input_message, sender_tag, ack_tag], initial_values=[z3p.IntVal(0), z3p.IntVal(0), z3p.IntVal(0)], input_channels=[send, timeout, backward_output_channel], output_channels=[forward_input_channel], variable_ranges={ input_message: (min_value_message, max_value_message), sender_tag: (0, 1), ack_tag: (0, 1) }, output_channel_ranges={ forward_input_channel[1]: (min_value_message, max_value_message), forward_input_channel[0]: (0, 1) })
def safety_monitor(): safety_data_sent = z3p.Int('safety_data_sent') safety_data_received = z3p.Int('safety_data_received') variable_ranges = { safety_data_sent: (min_value_message, max_value_message), safety_data_received: (min_value_message, max_value_message) } send = z3p.Int('send') receive = z3p.Int('receive') transitions = [] transitions.append(('t0', 'waiting_for_send', send, z3p.BoolVal(True), [(safety_data_sent, send)], 'waiting_for_receive')) transitions.append( ('t1', 'waiting_for_receive', receive, z3p.BoolVal(True), [(safety_data_received, receive)], 'check_received_data')) transitions.append(('t2', 'check_received_data', z3p.Neq(safety_data_sent, safety_data_received), [], 'error')) transitions.append(('t3', 'check_received_data', z3p.Eq(safety_data_sent, safety_data_received), [], 'waiting_for_send')) transitions.append( ('t4', 'waiting_for_send', receive, z3p.BoolVal(True), [], 'error')) transitions.append( ('t5', 'waiting_for_receive', send, z3p.BoolVal(True), [], 'error')) transitions.append(('t6', 'error', send, z3p.BoolVal(True), [], 'error')) transitions.append( ('t6', 'error', receive, z3p.BoolVal(True), [], 'error')) return automaton.SymbolicAutomaton( 'safety_monitor', [ 'waiting_for_send', 'waiting_for_receive', 'error', 'check_received_data' ], 'waiting_for_send', transitions, [safety_data_sent, safety_data_received], [z3p.IntVal(0), z3p.IntVal(0)], input_channels=[send, receive], variable_ranges=variable_ranges)
def environment(cache_id, directory_id, address_id, num_values): transitions = [] variables = [] variable_ranges = {} PendingStore = z3p.Int('pending_store_environment_{}_{}_{}'.format(cache_id, directory_id, address_id)) StoreResult = z3p.Int('store_result_{}_{}_{}'.format(cache_id, directory_id, address_id)) variable_ranges[PendingStore] = (0, num_values - 1) variable_ranges[StoreResult] = (0, num_values - 1) variables = [PendingStore, StoreResult] initial_values = [ZERO, ZERO] locations = ['Env{}_Initial'.format(cache_id), 'Env{}_PendingLD'.format(cache_id), 'Env{}_PendingST'.format(cache_id), 'Env{}_PendingEV'.format(cache_id), 'Env{}_Error'.format(cache_id)] # input messages suffix = '_{}_{}_{}'.format(cache_id, directory_id, address_id) LDAckMsg = z3p.Int('LDAckMsg' + suffix) STAckMsg = z3p.Int('STAckMsg' + suffix) EVAckMsg = util.new_variable('EVAckMsg' + suffix, 'unit') input_channels = [LDAckMsg, STAckMsg, EVAckMsg] # input_channels = [LDAckMsg] LDMsg = util.new_variable('LDMsg' + suffix, 'unit') STMsg = z3p.Int('STMsg' + suffix) EVMsg = util.new_variable('EVMsg' + suffix, 'unit') output_channels = [LDMsg, STMsg, EVMsg] # output_channels = [LDMsg] transitions = [] # // Load flow # Env_Initial send LDMsg[c][d][a] {} -> Env_PendingLD; # Env_PendingLD on LDAckMsg[c][d][a] (v) {} -> Env_Initial; transitions.append((None, 'Env{}_Initial'.format(cache_id), LDMsg, [ZERO], TRUE, [], 'Env{}_PendingLD'.format(cache_id))) transitions.append((None, 'Env{}_PendingLD'.format(cache_id), LDAckMsg, TRUE, [(PendingStore, LDAckMsg)], 'Env{}_Initial'.format(cache_id))) # // Store flow # foreach v in ValueType # Env_Initial send STMsg[c][d][a] (v) { PendingStore := v; } -> Env_PendingST; # Env_PendingST on STAckMsg[c][d][a] # if (v = PendingStore) {} -> Env_Initial; # if (v != PendingStore) {} -> Env_Error; for v in range(num_values): transitions.append((None, 'Env{}_Initial'.format(cache_id), STMsg, [z3p.IntVal(v)], TRUE, [(PendingStore, z3p.IntVal(v))], 'Env{}_PendingST'.format(cache_id))) transitions.append((None, 'Env{}_PendingST'.format(cache_id), STAckMsg, TRUE, [(StoreResult, STAckMsg)], 'Env{}_PendingST2'.format(cache_id))) transitions.append((None, 'Env{}_PendingST2'.format(cache_id), z3p.Eq(StoreResult, PendingStore), [(StoreResult, ZERO), (PendingStore, ZERO)], 'Env{}_Initial'.format(cache_id))) transitions.append((None, 'Env{}_PendingST2'.format(cache_id), z3p.Neq(StoreResult, PendingStore), [(StoreResult, ZERO), (PendingStore, ZERO)], 'Env{}_Error'.format(cache_id))) # // Evict flow # Env_Initial send EVMsg[c][d][a] {} -> Env_PendingEV; # Env_PendingEV on EVAckMsg[c][d][a] {} -> Env_Initial; transitions.append((None, 'Env{}_Initial'.format(cache_id), EVMsg, [ZERO], TRUE, [], 'Env{}_PendingEV'.format(cache_id))) transitions.append((None, 'Env{}_PendingEV'.format(cache_id), EVAckMsg, TRUE, [], 'Env{}_Initial'.format(cache_id))) locations.extend(['Env{}_PendingST2'.format(cache_id)]) return automaton.SymbolicAutomaton('enviroment_{}_{}_{}'.format(cache_id, directory_id, address_id), locations, 'Env{}_Initial'.format(cache_id), transitions, variables=variables, initial_values=initial_values, input_channels=input_channels, output_channels=output_channels, variable_ranges=variable_ranges)
def cache(c, num_caches=1, num_values=1, num_addresses=1, num_directories=1): transitions = [] variables = [] variable_ranges = {} DataBlk = z3p.Int('DataBlk_{}'.format(c)) AckCounter = z3p.Int('AckCounter_{}'.format(c)) PendingWrite = z3p.Int('PendingWrite_{}'.format(c)) FwdToCache = z3p.Int('FwdToCache_{}'.format(c)) NumAcksTemp = z3p.Int('NumAcksTemp_{}'.format(c)) variable_ranges = {DataBlk: (0, num_values - 1), AckCounter: (-num_caches, num_caches), PendingWrite: (0, num_values - 1), FwdToCache: (0, num_caches - 1), NumAcksTemp: (0, num_caches)} variables = [DataBlk, AckCounter, PendingWrite, FwdToCache, NumAcksTemp] initial_values = [ZERO, ZERO, ZERO, ZERO, ZERO] # ??? initial_values # input messages input_channels = [] for d in range(num_directories): for a in range(num_addresses): input_channels.extend([LDMsg[c][d][a], STMsg[c][d][a], EVMsg[c][d][a], FwdGetXMsgP[c][d][a], FwdGetSMsgP[c][d][a], DataMsgD2CP[c][d][a], WBAckMsgP[c][d][a]]) for c2 in range(num_caches): if c2 != c: for d in range(num_directories): for a in range(num_addresses): input_channels.extend([DataMsgC2CP[c2][c][d][a], InvAckMsgP[c2][c][d][a]]) # output messages output_channels = [] for d in range(num_directories): for a in range(num_addresses): output_channels.extend([LDAckMsg[c][d][a], STAckMsg[c][d][a], EVAckMsg[c][d][a], UnblockSMsg[c][d][a], UnblockEMsg[c][d][a], GetXMsg[c][d][a], GetSMsg[c][d][a], WBMsg[c][d][a]]) for c2 in range(num_caches): if c2 != c: output_channels.extend([DataMsgC2C[c][c2][d][a], InvAckMsg[c][c2][d][a]]) for d in range(num_directories): for a in range(num_addresses): # // Transitions from I for Ext events # C_I on LDMsg[c][d][a] {} -> send GetSMsg[c][d][a] {} -> C_IS; # C_I on STMsg[c][d][a] (v) { PendingWrite := v; } -> # send GetXMsg[c][d][a] {} -> C_IM; # C_I on EVMsg[c][d][a] {} -> send EVAckMsg[c][d][a] -> C_I; transitions.append((None, 'C_I', LDMsg[c][d][a], TRUE, [], 'C_I2')) transitions.append((None, 'C_I2', GetSMsg[c][d][a], [], TRUE, [], 'C_IS')) transitions.append((None, 'C_I', STMsg[c][d][a], TRUE, [(PendingWrite, STMsg[c][d][a])], 'C_I3')) transitions.append((None, 'C_I3', GetXMsg[c][d][a], [], TRUE, [], 'C_IM')) transitions.append((None, 'C_I', EVMsg[c][d][a], TRUE, [], 'C_I4')) transitions.append((None, 'C_I4', EVAckMsg[c][d][a], [], TRUE, [], 'C_I')) # // Transitions for I on Fwd events # C_I on FwdGetSMsg'[c][d][a] (c2) { FwdToCache := c2; } -> # send InvAckMsg[c][FwdToCache][d][a] { FwdToCache := undef; } -> C_I; transitions.append((None, 'C_I', FwdGetSMsgP[c][d][a], TRUE, [(FwdToCache, FwdGetSMsgP[c][d][a])], 'C_I5')) for other_c in range(num_caches): if other_c != c: transitions.append((None, 'C_I5', InvAckMsg[c][other_c][d][a], [], z3p.Eq(INT(other_c), FwdToCache), [(FwdToCache, ZERO)], 'C_I')) # // Transitions from S on Ext Events # C_S on LDMsg[c][d][a] {} -> send LDAckMsg[c][d][a] (DataBlk) -> C_S; transitions.append((None, 'C_S', LDMsg[c][d][a], TRUE, [], 'C_S2')) transitions.append((None, 'C_S2', LDAckMsg[c][d][a], [DataBlk], TRUE, [], 'C_S')) # C_S on STMsg[c][d][a] (v) { PendingWrite := v; } -> # send GetXMsg[c][d][a] {} -> C_SM; transitions.append((None, 'C_S', STMsg[c][d][a], TRUE, [(PendingWrite, STMsg[c][d][a])], 'C_S3')) transitions.append((None, 'C_S3', GetXMsg[c][d][a], [], TRUE, [], 'C_SM')) # C_S on EVMsg[c][d][a] {} -> # send EVAckMsg[c][d][a] { DataBlk := undef; } -> C_I; transitions.append((None, 'C_S', EVMsg[c][d][a], TRUE, [], 'C_S4')) transitions.append((None, 'C_S4', EVAckMsg[c][d][a], [], TRUE, [(DataBlk, ZERO)], 'C_I')) # // Transitions from S on Fwd events # C_S on FwdGetXMsg[c][d][a] (c2) { FwdToCache := c2; } -> # send InvAckMsg[c][FwdToCache][d][a] { DataBlk := undef } -> C_I; transitions.append((None, 'C_S', FwdGetXMsgP[c][d][a], TRUE, [(FwdToCache, FwdGetXMsgP[c][d][a]), (DataBlk, ZERO)], 'C_S5')) for other_c in range(num_caches): if other_c != c: transitions.append((None, 'C_S5', InvAckMsg[c][other_c][d][a], [], z3p.Eq(z3p.IntVal(other_c), FwdToCache), [(FwdToCache, ZERO)], 'C_I')) # // Transitions from M on Ext events # C_M on LDMsg[c][d][a] {} -> send LDAckMsg[c][d][a] (DataBlk) {} -> C_M; transitions.append((None, 'C_M', LDMsg[c][d][a], TRUE, [], 'C_M2')) transitions.append((None, 'C_M2', LDAckMsg[c][d][a], [DataBlk], TRUE, [], 'C_M')) # C_M on STMsg[c][d][a] (v) { DataBlk := v; } -> # send STAckMsg[c][d][a] (DataBlk) {} -> C_M; transitions.append((None, 'C_M', STMsg[c][d][a], TRUE, [(DataBlk, STMsg[c][d][a])], 'C_M3')) transitions.append((None, 'C_M3', STAckMsg[c][d][a], [DataBlk], TRUE, [], 'C_M')) # C_M on EVMsg[c][d][a] {} -> send WBMsg[c][d][a] (DataBlk) {} -> C_II; transitions.append((None, 'C_M', EVMsg[c][d][a], TRUE, [], 'C_M4')) transitions.append((None, 'C_M4', WBMsg[c][d][a], [DataBlk], TRUE, [], 'C_II')) # // Transitions from M on Fwd events # C_M on FwdGetSMsg'[c][d][a] (c2) { FwdToCache := c2; } -> # send DataMsgC2C[c][FwdToCache][d][a] (DataBlk) { FwdToCache := undef; } -> C_S; transitions.append((None, 'C_M', FwdGetSMsgP[c][d][a], TRUE, [(FwdToCache, FwdGetSMsgP[c][d][a])], 'C_M5')) for other_c in range(num_caches): if other_c != c: transitions.append((None, 'C_M5', DataMsgC2C[c][other_c][d][a], [DataBlk], z3p.Eq(z3p.IntVal(other_c), FwdToCache), [(FwdToCache, ZERO)], 'C_S')) # C_M on FwdGetXMsg'[c][d][a] (c2) { FwdToCache := c2; } -> # send DataMsgC2C[c][FwdToCache][d][a] (DataBlk) # { FwdToCache := undef; DataBlk := undef; } -> C_I; transitions.append((None, 'C_M', FwdGetXMsgP[c][d][a], TRUE, [(FwdToCache, FwdGetXMsgP[c][d][a])], 'C_M6')) for other_c in range(num_caches): if other_c != c: transitions.append((None, 'C_M6', DataMsgC2C[c][other_c][d][a], [DataBlk], z3p.Eq(z3p.IntVal(other_c), FwdToCache), [(FwdToCache, ZERO), (DataBlk, ZERO)], 'C_I')) # // Transitions from C_IM on Rsp Events # C_IM on FwdGetXMsg'[c][d][a] (c2) { FwdToCache := c2; } -> # send InvAckMsg[c][FwdToCache][d][a] {FwdToCache := undef; } -> C_IM; transitions.append((None, 'C_IM', FwdGetXMsgP[c][d][a], TRUE, [(FwdToCache, FwdGetXMsgP[c][d][a])], 'C_IM2')) for other_c in range(num_caches): if other_c != c: transitions.append((None, 'C_IM2', InvAckMsg[c][other_c][d][a], [DataBlk], z3p.Eq(INT(other_c), FwdToCache), [(FwdToCache, ZERO)], 'C_IM')) # // Case when another cache gives me data # foreach c2 in CacheIDType (!= c2 c) { # C_IM on DataMsgC2C'[c2][c][d][a] (v) { DataBlk := v; } -> C_M; # } for other_c in range(num_caches): if other_c != c: transitions.append((None, 'C_IM', DataMsgC2CP[other_c][c][d][a], TRUE, [(DataBlk, DataMsgC2CP[other_c][c][d][a])], 'C_M')) # // Case when data comes from dir ==> Must wait for acks # C_IM on DataMsgD2C'[c][d][a] (v, NumAcks) # if (!= AckCounter NumAcks) # { AckCounter := (- AckCounter NumAcks); DataBlk := v; } -> C_SM; # if (= AckCounter NumAcks) # { AckCounter := 0; DataBlk := v; } -> # send UnblockEMsg[c][d][a] { DataBlk := PendingStore; PendingStore := undef; } -> C_M; transitions.append((None, 'C_IM', DataMsgD2CP[c][d][a], TRUE, [(DataBlk, DataMsgD2CP[c][d][a][0]), (NumAcksTemp, DataMsgD2CP[c][d][a][1])], 'C_IM3')) transitions.append((None, 'C_IM3', z3p.Neq(AckCounter, NumAcksTemp), [(AckCounter, AckCounter - NumAcksTemp), (NumAcksTemp, ZERO)], 'C_SM')) transitions.append((None, 'C_IM3', z3p.Eq(AckCounter, NumAcksTemp), [(AckCounter, ZERO), (NumAcksTemp, ZERO)], 'C_IM4')) transitions.append((None, 'C_IM4', STAckMsg[c][d][a], [PendingWrite], TRUE, [(DataBlk, PendingWrite), (PendingWrite, ZERO)], 'C_IM5')) transitions.append((None, 'C_IM5', UnblockEMsg[c][d][a], [ZERO], TRUE, [], 'C_M')) # foreach c2 in CacheIDType (!= c2 c) { # C_IM on InvAckMsg[c2][c][d][a] { AckCounter := (+ AckCounter 1); } -> C_IM; # } for other_c in range(num_caches): if other_c != c: transitions.append((None, 'C_IM', InvAckMsgP[other_c][c][d][a], TRUE, [(AckCounter, AckCounter + 1)], 'C_IM')) # // Transitions from C_SM on Ext Events # C_SM on LDMsg[c][d][a] {} -> send LDAckMsg[c][d][a] (DataBlk) {} -> C_SM; transitions.append((None, 'C_SM', LDMsg[c][d][a], TRUE, [], 'C_SM2')) transitions.append((None, 'C_SM2', LDAckMsg[c][d][a], [DataBlk], TRUE, [], 'C_SM')) # // Transitions from C_SM on Rsp Events # C_SM on FwdGetXMsg'[c][d][a] (c2) { FwdToCache := c2; } -> # send InvAckMsg[c][FwdToCache][d][a] {} -> C_SM; transitions.append((None, 'C_SM', FwdGetXMsgP[c][d][a], TRUE, [(FwdToCache, FwdGetXMsgP[c][d][a])], 'C_SM3')) for other_c in range(num_caches): if other_c != c: transitions.append((None, 'C_SM3', InvAckMsg[c][other_c][d][a], [], z3p.Eq(z3p.IntVal(other_c), FwdToCache), [], 'C_IM')) # // Case where data comes from dir ==> Must wait for acks # C_SM on DataMsgD2C'[c][d][a] (v, NumAcks) transitions.append((None, 'C_SM', DataMsgD2CP[c][d][a], TRUE, [(NumAcksTemp, DataMsgD2CP[c][d][a][1])], 'C_SM4')) # if (= NumAcks AckCounter) { AckCounter := 0; } -> # send UnblockEMsg[c][d][a] { DataBlk := PendingStore; PendingStore := undef; } -> # send STAckMsg[c][d][a] (DataBlk) {} -> C_M; # if (!= NumAcks AckCounter) { AckCounter := (- AckCounter NumAcks) } -> C_SM; transitions.append((None, 'C_SM4', UnblockEMsg[c][d][a], [ZERO], z3p.Eq(NumAcksTemp, AckCounter), [(DataBlk, PendingWrite), (PendingWrite, ZERO), (NumAcksTemp, ZERO), (AckCounter, ZERO)], 'C_SM5')) transitions.append((None, 'C_SM5', STAckMsg[c][d][a], [DataBlk], TRUE, [], 'C_M')) transitions.append((None, 'C_SM4', z3p.Neq(NumAcksTemp, AckCounter), [(AckCounter, AckCounter - NumAcksTemp), (NumAcksTemp, ZERO)], 'C_SM')) # foreach c2 in CacheIDType (!= c2 c) { # C_SM on InvAckMsg'[c2][c][d][a] # if (= AckCounter (- 1)) { AckCounter := 0; } -> # send UnblockEMsg[c][d][a] { DataBlk := PendingStore; PendingStore := undef; } -> # send STAckMsg[c][d][a] (DataBlk) {} -> C_M; # if (!= AckCounter (- 1)) { AckCounter := (+ AckCounter 1); } -> # send UnblockEMsg[c][d][a] { DataBlk := PendingStore; PendingStore := undef; } -> # send STAckMsg[c][d][a] (DataBlk) {} -> C_M; # } for other_c in range(num_caches): if other_c != c: transitions.append((None, 'C_SM', InvAckMsgP[other_c][c][d][a], z3p.Eq(AckCounter, -ONE), [(AckCounter, ZERO), (DataBlk, PendingWrite), (PendingWrite, ZERO)], 'C_SM6')) transitions.append((None, 'C_SM6', UnblockEMsg[c][d][a], [DataBlk], TRUE, [], 'C_SM7')) transitions.append((None, 'C_SM7', STAckMsg[c][d][a], [DataBlk], TRUE, [], 'C_M')) transitions.append((None, 'C_SM', InvAckMsgP[other_c][c][d][a], z3p.Neq(AckCounter, -ONE), [(AckCounter, AckCounter + 1)], 'C_SM')) # transitions.append((None, 'C_SM6', UnblockEMsg[c][d][a], [DataBlk], TRUE, [], 'C_SM7')) # transitions.append((None, 'C_SM7', STAckMsg[c][d][a], [DataBlk], TRUE, [], 'C_M')) # transitions.append((None, 'C_SM', InvAckMsgP[other_c][c][d][a], TRUE, [], 'C_SM6')) # transitions.append((None, 'C_SM6', UnblockEMsg[c][d][a], [ZERO], z3p.Eq(AckCounter, - ONE), [(AckCounter, ZERO), (DataBlk, PendingWrite), (PendingWrite, ZERO)], 'C_SM6')) # transitions.append((None, 'C_SM7', STAckMsg[c][d][a], [DataBlk], TRUE, [], 'C_M')) # transitions.append((None, 'C_SM6', UnblockEMsg[c][d][a], [], z3p.Neq(AckCounter, ZERO - ONE), [(AckCounter, AckCounter + 1), (DataBlk, PendingWrite), (PendingWrite, ZERO)], 'C_SM7')) # transitions.append((None, 'C_SM8', STAckMsg[c][d][a], [DataBlk], TRUE, [], 'C_M')) # // Transitions from IS on Ext Events # C_IS on FwdGetXMsg'[c][d][a] (c2) { FwdToCache := c2; } -> # send InvAckMsg[c][FwdToCache][d][a] {} -> C_IS; transitions.append((None, 'C_IS', FwdGetXMsgP[c][d][a], TRUE, [(FwdToCache, FwdGetXMsgP[c][d][a])], 'C_IS2')) for other_c in range(num_caches): if other_c != c: transitions.append((None, 'C_IS2', InvAckMsg[c][other_c][d][a], [], z3p.Eq(INT(other_c), FwdToCache), [], 'C_IS')) # // Transitions on IS on Rsp Events # C_IS on DataMsgD2C'[c][d][a] (v, _) { DataBlk := v; } -> # send UnblockSMsg[c][d][a] {} -> send LDAckMsg[c][d][a] (DataBlk) {} -> C_S; transitions.append((None, 'C_IS', DataMsgD2CP[c][d][a], TRUE, [(DataBlk, DataMsgD2CP[c][d][a][0])], 'C_IS3')) transitions.append((None, 'C_IS3', UnblockSMsg[c][d][a], [ZERO], TRUE, [], 'C_IS4')) transitions.append((None, 'C_IS4', LDAckMsg[c][d][a], [DataBlk], TRUE, [], 'C_S')) # foreach c2 in CacheIDType (!= c2 c) { # C_IS on DataMsgC2C'[c2][c][d][a] (v) -> { DataBlk := v; } -> # send UnblockSMsg[c][d][a] -> send LDAckMsg[c][d][a] (DataBlk) -> C_S; # } for other_c in range(num_caches): if other_c != c: transitions.append((None, 'C_IS', DataMsgC2CP[other_c][c][d][a], TRUE, [(DataBlk, DataMsgC2CP[other_c][c][d][a])], 'C_IS3')) # transitions.append((None, 'C_IS4', UnblockSMsg[c][d][a], [ZERO], TRUE, [], 'C_IS5')) # transitions.append((None, 'C_IS5', LDAckMsg[c][d][a], [DataBlk], TRUE, [], 'C_S')) # // Transitions on II on Rsp Events # C_II on WBAckMsg'[c][d][a] -> C_I; # send EVAck and then go to C_I transitions.append((None, 'C_II', WBAckMsgP[c][d][a], TRUE, [], 'C_II2')) transitions.append((None, 'C_II2', EVAckMsg[c][d][a], [ZERO], TRUE, [], 'C_I')) # C_II on FwdGetXMsg'[c][d][a] (c2) { FwdToCache := c2; } -> # send InvAckMsg[c][FwdToCache][d][a] -> C_I; transitions.append((None, 'C_II', FwdGetXMsgP[c][d][a], TRUE, [(FwdToCache, FwdGetXMsgP[c][d][a])], 'C_I5')) # for other_c in range(num_caches): # if other_c != c: # transitions.append((None, 'C_II2', InvAckMsg[c][other_c][d][a], [], z3p.Eq(FwdToCache, other_c), [(FwdToCache, ZERO)], 'C_I')) # C_II on FwdGetSMsg'[c][d][a] (_) -> I; # } transitions.append((None, 'C_II', FwdGetSMsgP[c][d][a], TRUE, [], 'C_I')) locations = ['C_I', 'C_S', 'C_M', 'C_IM', 'C_SM', 'C_IS', 'C_II'] locations.extend(['C_I2', 'C_I3', 'C_I4', 'C_I5']) locations.extend(['C_S2', 'C_S3', 'C_S4', 'C_S5']) locations.extend(['C_M2', 'C_M3', 'C_M4', 'C_M5', 'C_M6']) locations.extend(['C_IM2', 'C_IM3', 'C_IM4', 'C_IM5']) locations.extend(['C_SM2', 'C_SM3', 'C_SM4', 'C_SM5', 'C_SM6', 'C_SM7', 'C_SM8']) locations.extend(['C_IS2', 'C_IS3', 'C_IS4']) # , 'C_IS5']) locations.extend(['C_II2']) return automaton.SymbolicAutomaton('cache{}'.format(c), locations, 'C_I', transitions, variables=variables, initial_values=initial_values, input_channels=input_channels, output_channels=output_channels, variable_ranges=variable_ranges)
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 transitions_from_state(self, state1, state2, verbose=0): possible_transitions = dict([(a, []) for a in self.automata]) possible_channels = dict([(a, set([])) for a in self.automata]) possible_internal_transitions = dict([(a, []) for a in self.automata]) transition_channels = {} for a in self.automata: if state1[a] == state2[a]: possible_transitions[a].append(None) for t in a.edges(data=True): if a.can_transition(state1[a], state2[a], t): possible_transitions[a].append(t) channel = t[2]['channel'] if channel is None: possible_internal_transitions[a].append(t) else: possible_channels[a].add(channel) for a in self.automata: for c in list(possible_channels[a]): assert c in self.readers, "{} not in {}".format(c, self.readers) assert c in self.writer, "{} not in {}".format(c, self.writer) automata = self.readers[c] + [self.writer[c]] if (any(c not in possible_channels[ap] for ap in automata) or any(None not in possible_transitions[ap] for ap in self.automata if ap not in automata)): possible_channels[a].remove(c) if any(len(possible_channels[a]) > 0 for a in self.automata): c = next(list(possible_channels[a])[0] for a in self.automata if len(possible_channels[a]) > 0) if verbose > 0: print "Checking channel {}".format(c) for t in possible_transitions[self.writer[c]]: writer_transition = t if verbose > 0: print "Checking writer transition {}".format(t) if t is not None and t[2]['channel'] == c: channel_expressions = t[2]['channel_expression'] channel_expression_values = [util.evaluate_expression(channel_expression, {}, state1[self.writer[c]], tables=self.writer[c].tables) for channel_expression in channel_expressions] if verbose > 0: print 'Writer tables are {}'.format(self.writer[c].tables) print 'Channel expressions are {}'.format(channel_expressions) print 'Channel expression values are {}'.format(channel_expression_values) reader_transitions = [next(t for t in possible_transitions[a] if t is not None and t[2]['channel'] == c) for a in self.readers[c]] writer_matches_readers = True for rt in reader_transitions: if verbose > 0: print "Checking against reader transition {}".format(rt) ra = rt[2]['automaton'] updates = rt[2]['update'] for update in updates: if c in z3p.variables_in_expression(update[1]): if isinstance(c, z3p.ArrayRef): selects = util.selects_in_expression(update[1]) new_reader_concrete_memory = dict(state1[ra]) for select in selects: index = select.arg(1) new_reader_concrete_memory[c[index]] = channel_expression_values[index.as_long()] if state2[ra][update[0]] != util.evaluate_expression(update[1], {}, new_reader_concrete_memory): writer_matches_readers = False else: new_reader_concrete_memory = dict(state1[ra]) new_reader_concrete_memory[c] = channel_expression_values[0] s = z3p.Solver() s.add(z3p.Neq(state2[ra][update[0]], util.evaluate_expression(update[1], {}, new_reader_concrete_memory))) if s.check() != z3p.unsat: if verbose: print "update does not match {}, {}".format(state2[ra][update[0]], util.evaluate_expression(update[1], {}, new_reader_concrete_memory)) writer_matches_readers = False if writer_matches_readers: return [writer_transition] + reader_transitions else: for a in self.automata: other_automata = [ap for ap in self.automata if a != ap] if (len(possible_internal_transitions[a]) > 0 and all(None in possible_transitions[ap] for ap in other_automata)): return [possible_internal_transitions[a]]