发布于 2012-09-22 10:52:28
6楼
可以这样分析(最好准备纸笔,把堆栈的变化记录下来):
LD M16.3 // TOS(栈顶)=M16.3
LPS // 压栈,即栈顶(TOS)及栈顶下一级(IV1)均为M16.3
A I3.3 // TOS=M16.3 and I3.3
S M16.0, 1 //逻辑代数式: M16.0 = M16.0 + M16.3 and I3.3
LRD // 将IV1复制到TOS,即此时TOS=M16.3
A I3.6 // TOS=M16.3 and I3.6
EU // TOS=(M16.3 and I3.6)↑
LDS 1 // 取出IV1(此时IV1=M16.3)然后堆栈下压一级,将刚取出的值复制到栈顶,指令完成后,TOS=M16.3,IV1=(M16.3 and I3.6)↑
A T38 // TOS=M16.3 and T38
OLD // 将TOS和IV1或起来,即TOS=(M16.3 and T38) or (M16.3 and I3.6)↑
R Q1.2, 1 // 逻辑代数式:Q1.2=Q1.2 and (not ((M16.3 and T38) or (M16.3 and I3.6)↑)
这段程序,M16.3被用了很多次,但只在开头读取一次,用堆栈保存中间多次运算需要的M16.3。
根据得出的逻辑代数式,可以不用堆栈保存M16.3,每次都重新读取,程序就变成这样了:
Network 1
// 网络注释
LD M16.3 // TOS(栈顶)=M16.3
A I3.3 // TOS=M16.3 and I3.3
S M16.0, 1 // M16.0 = M16.0 + M16.3 and I3.3
Network 2
LD M16.3
A T38 // TOS=M16.3 and T38
LD M16.3 // 堆栈下压一级,TOS=M16.3,IV1=M16.3 and T38
A I3.6 // TOS=M16.3 and I3.6
EU // TOS=(M16.3 and I3.6)↑
OLD // 将TOS和IV1或起来,即TOS=(M16.3 and T38) or (M16.3 and I3.6)↑
R Q1.2, 1 // Q1.2=Q1.2 and (not ((M16.3 and T38) or (M16.3 and I3.6)↑)
而且现在这段程序可以转为LAD了。
好,那么这两段程序有什么区别。绝大多次情况是等效的。但如果你把程序改[写后,出现不稳定情况,这种隐蔽的问题是非常难以发现的。
原始那段程序,M16.3只读取一次,在这段程序执行其间,不怕M16.3可能发生变化(比如中断可能修改M16.3);
后面那段等效程序,M16.3读了三次,就要求写程序的人心中清楚这三次读得的是不是100%是同一个值。这种情况,可以叫做数据的完整性。