SIC/XE中+JSUB与LDA解引用行为差异的技术问询
问题背景
我正在学习SIC/XE汇编语言,在寻址模式方面遇到了困惑。以下是两段测试代码:
代码示例1
MOJPRG START 0 +JSUB #WRREC HALT J HALT WRREC RSUB
代码示例2
MOJPRG START 0 +JSUB WRREC HALT J HALT WRREC RSUB
这两段程序都能正确执行:CPU会跳转到WRREC并最终返回。
根据我对LDA指令的理解:
LDA NUMBER(简单寻址):对NUMBER地址处的内存进行一次解引用,将值加载到A寄存器中。LDA #NUMBER(立即寻址):直接将字面量NUMBER加载到A寄存器中。
因此我预期JSUB指令遵循相同规则:
JSUB WRREC应该跳转到WRREC地址中的内容(进行一次解引用)。JSUB #WRREC应该跳转到字面量值(即WRREC的地址本身)。
但实际行为是:
+JSUB WRREC直接跳转到WRREC的地址——未发生解引用。+JSUB #WRREC有时也会直接跳转到WRREC的地址。
具体问题
- 为何
JSUB即使在简单寻址模式下也不像LDA那样进行解引用? - SIC/XE中是否有正式规则说明控制流指令(如
JSUB)与数据指令在寻址模式交互上的差异? #符号是否应与JSUB配合使用,还是仅适用于数据指令?
解答
1. JSUB不做解引用的原因
SIC/XE的控制流指令(包括JSUB、J、JEQ等)的寻址模式语义和数据指令本质不同。数据指令(如LDA、STA)的目标是操作内存中的数据,所以简单寻址会去取地址对应内存的值;但控制流指令的目标是获取跳转的目标代码地址,而非该地址存储的数据。
对于JSUB WRREC,汇编器会直接把WRREC的符号地址作为跳转目标编码到指令中,CPU执行时直接用这个地址跳转,不会去解引用该地址的内容——因为控制流指令的设计逻辑就是直接定位到要执行的代码地址,而不是读取地址里的数据再跳转(这种间接跳转在SIC/XE里有专门的实现方式,比如通过寄存器寻址或者扩展寻址的间接位)。
2. 正式规则说明
SIC/XE的指令集规范明确区分了数据操作指令和控制转移指令的寻址模式行为:
- 数据指令(加载、存储、算术运算类):简单寻址模式下,计算出的有效地址是数据的存储地址,指令会对该地址进行读写操作(即解引用)。
- 控制转移指令(跳转、子程序调用类):简单寻址模式下,计算出的有效地址就是目标代码的执行地址,指令直接把PC设置为该地址,不会对地址进行解引用。
另外,+JSUB是SIC/XE的扩展指令(3字节),其寻址模式的处理逻辑也遵循控制流指令的规则:不管用不用#,只要是符号地址,汇编器都会直接把符号对应的地址作为跳转目标——这里的#在控制流指令里实际上是无效的,汇编器会忽略它,或者把它当作直接地址处理,所以才会出现+JSUB #WRREC也跳转到WRREC地址的情况。
3. #符号的适用场景
#符号是立即寻址的标记,仅适用于数据指令(如LDA、ADD等),用来表示直接加载字面量值,而非解引用内存地址。
对于控制流指令(如JSUB),#符号没有意义,因为控制流指令本身就是直接使用目标地址,不需要立即寻址的语义。汇编器遇到+JSUB #WRREC时,通常会把#当作冗余符号处理,直接使用WRREC的地址作为跳转目标,所以这种写法是不规范的,不建议使用。
内容的提问来源于stack exchange,提问作者ab55

