移位和循环指令允许累加器或内存位置中的位向上(左)或向下(右)移动一个位置。当位被移动时,将需要一个新值来填充在值一端创建的空位置,同样地,在另一端移位的位也需要被捕获和存储。
移位和循环都捕获进位标志中的移位位,但它们在填补空缺位置的方式上有所不同;移位将总是用零填充空位,而循环将用进位标志的值填充它,就像在指令开始时一样。
例如下图展示了对数值为$4D
进行算术左移(ASL)
操作后得到$9A
的过程。
+---+---+---+---+---+---+---+---+
Initial: | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 |
+---+---+---+---+---+---+---+---+
| | | | | | | |
/ / / / / / / /
/ / / / / / / / 0
/ / / / / / / / /
/ | | | | | | | |
/ v v v v v v v v
+---+---+---+---+---+---+---+---+
Result: C=0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 |
+---+---+---+---+---+---+---+---+
下面这张图中展示了使用左循环(ROL)
指令对$4D
操作得到$9A
的过程。
+---+---+---+---+---+---+---+---+
Initial: | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | C=1
+---+---+---+---+---+---+---+---+
| | | | | | | | /
/ / / / / / / / /
/ / / / / / / / /
/ / / / / / / / /
/ | | | | | | | |
/ v v v v v v v v
+---+---+---+---+---+---+---+---+
Result: C=0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 1 |
+---+---+---+---+---+---+---+---+
移动一个二进制数内位置上的数值(并且引入一个数字0作为最低有效位)的效果相当于将其乘以2。因此这是一种更加简洁的乘法计算方法。为了让这种方法适用于大于一个字节的数据,我们使用ASL
指令来移动第一个字节的数据,然后使用ROL
指令对后续的字节进行操作,遇到跨字节移位的时候还可以使用进位标志(CF)对跨字节移位的数据进行存储。
; Shift a 16bit value by one place left (e.g. multiply by two)
_ASL16 ASL MEM+0 ;Shift the LSB
ROL MEM+1 ;Rotate the MSB
和左移/左循环类似,右移/右循环操作也遵循同样的模式。例如,我们可以用逻辑右移(LSR)
对$4D
进行操作,从而得到$26
。
+---+---+---+---+---+---+---+---+
Initial: | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 |
+---+---+---+---+---+---+---+---+
| | | | | | | |
\ \ \ \ \ \ \ \
0 \ \ \ \ \ \ \ \
\ \ \ \ \ \ \ \ \
| | | | | | | | \
v v v v v v v v \
+---+---+---+---+---+---+---+---+
Result: | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | C=1
+---+---+---+---+---+---+---+---+
或者使用右循环(ROR)
指令对同一个数值进行操作,但是假设包含了数值$A6
的进位1。
+---+---+---+---+---+---+---+---+
Initial: C=1 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 |
+---+---+---+---+---+---+---+---+
\ | | | | | | | |
\ \ \ \ \ \ \ \ \
\ \ \ \ \ \ \ \ \
\ \ \ \ \ \ \ \ \
| | | | | | | | \
v v v v v v v v \
+---+---+---+---+---+---+---+---+
Result: | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | C=1
+---+---+---+---+---+---+---+---+
通过观察,我们可以看到右移操作实际上是左移操作的逆运算。左移相当于乘以2,那么右移就相当于除以2。同样,我们如果对多字节的值应用除法,通常先对第一个字节进行过LSR
操作(此时是从最高有效位MSB开始),然后对后续的字节进行ROR
操作。
; Shift a 16 bit value by one place right (e.g. divide by two)
_LSR16 LSR MEM+1 ;Shift the MSB
ROR MEM+0 ;Rotate the LSB
移位和循环操作是非常有用的指令,尤其是在处理通用乘法和除法运算时。
正如前面指出的那样,右移一个值2除以2只适用于无符号值。这是因为LSR将总是在MSB的最有效位放置一个零。为了让这个算法对所有两个补码编码的值都有效,我们需要确保这个位的值被复制回自身,以保持这个值的符号相同。我们可以利用另一个转变来实现这一点。
; Divide a signed 16 bit value by two
_DIV2 LDA MEM+1 ;Load the MSB
ASL A ;Copy the sign bit into C
ROR MEM+1 ;And back into the MSB
ROR MEM+0 ;Rotate the LSB as normal
网友评论