---------------------------- MODULE bank_account_assembly ---------------------------- \* Copyright (c) 2017, Gene Cooperman. May be freely distributed \* and modified as long as this copyright notice remains. \* Joint bank account by husband and wife; Only assembly statements (not C) \* are assumed atomic. This version models the code at assembly level, \* and so the "if" statement is no longer atomic. It will assert an error \* when total /= 120, even though initially, account = 100, and \* cash["husband"] = cash["wife"] = 10. \* In the "Model" sub-window, try initializing the constant "N" to 1. \* \* Note that if you remove the labels \* w0b, w0c, w1b, d0b, d0c, d1b, then there will be no assertion error. EXTENDS Naturals, Sequences, TLC \* Sequences required for "procedure" stmt CONSTANT N \* N is number of iterations. Assign to it in model overview. (* --algorithm bank { variables account = 100, cash = [i \in {"husband", "wife"} |-> 10], iterations = [i \in {"husband", "wife"} |-> N]; \* Note that we need to define iterations["husband"] and iterations["wife"]. \* We do _not_ want a single global variable, iterations, that is \* shared between "husband" and "wife". \* In model, replace "N" (a constant) by value for iterations \* The procedures withdraw and deposit have been translated here \* to pseudo-assembly language \* Note that "register1" and "register2" were declared as local variables \* inside the processes for husband and wife. procedure withdraw(amount1) variable register1, register2; { withdraw_start: register1 := amount1; \* lw register1, (amount1) w0b: register2 := account - register1; \* lw register2, (account) ; sub register2, register2, register1 w0c: account := register2; \* sw register2, (account) w1: register2 := cash[self] + register1; \* lw register2, (cash[self]) ; add register2, register2, register1 w1b: cash[self] := register2; \* sw register2, (cash[self]) w2: return; } procedure deposit(amount1) variable register1, register2; { deposit_start: register1 := amount1; \* lw register1, (amount1) d0b: register2 := account + register1; \* lw register2, (account) \* add register2, register2, register1 d0c: account := register2; \* sw register2, (account) d1: register2 := cash[self] - register1; \* lw register2, (cash[self]) \* sub register2, register2, register1 d1b: cash[self] := register2; \* sw register2, (cash[self]) d2: return; } process (spouse \in {"husband", "wife"}) variable total; { start: while (iterations[self] > 0) { \* We hard-wire the max amount below, but this could have been a CONSTANT. s1: with (amount \in 1..2) call withdraw(amount); s2: with (amount \in 1..2) call deposit(amount); s3: iterations[self] := iterations[self] - 1; total := account + cash["husband"] + cash["wife"]; }; assert iterations[self] = 0; if (iterations["husband"] = 0 /\ iterations["wife"] = 0) { total := account + cash["husband"] + cash["wife"]; print total; assert total = 120 ; } } \* end process block } \* end algorithm *) ====================