assembly 如何在没有XOR指令的CPU上执行XOR

rqdpfwrv  于 11个月前  发布在  其他
关注(0)|答案(4)|浏览(132)

这是一个更有趣的问题。我正在使用SC 61860 CPU,这是一个8位CPU,用于1987年的夏普PC-1360掌上电脑(也用于PC-1401和1403)。它的指令集实际上不包括XOR。它有AND,OR,比较,减法和加法指令。
我已经尝试了几种不同的AND和OR值来得到XOR会产生的结果,但没有运气。我希望避免比较,但看起来我没有选择。
如果你感兴趣,你可以看看instruction set(替代githubPC-1350 reference)。
顺便说一句,这款CPU非常适合学习汇编语言。它既漂亮又简单,而且速度足够慢(768 kHz),机器语言明显比使用BASIC内置的计算机快;)我通常用C/C++/Java编程。汇编语言是一股新鲜空气。

efzxgjgh

efzxgjgh1#

从布尔代数我们知道:

A XOR B = (NOT(A) AND B) OR (A AND NOT(B))

字符串

更新:感谢@Brett黑尔,@slebetman,因为CPU令人惊讶地不支持NOT指令,它可以通过算术否定和减法来模拟,假设2的补码否定表示):

NOT(A) = (-1) - A


或者在不同的否定表示的情况下,-1可以由相应的存储类型最大值(即,对于8位寄存器为255,对于16位寄存器为65565)替换。

wh6knrhe

wh6knrhe2#

正如@harold指出的,a ^ b = (a | b) - (a & b)
这也是对异或的一个回答,只有或和与-并集减去交集,没有借位。
这个运算集只能与内存目标(或与累加器中的立即数)进行AND或OR运算,而不能在它的主要和次要运算符(AB)之间进行AND或OR运算。看起来访问B的指令只是将其视为B:A中16位整数的高半部分,将B与A交换,或将其增加/减少。
所以我们需要在P指向的“内部”RAM中有一些暂存空间,因为ANMA[P] and A -> [P]是唯一的按位AND,其中两个操作数都是运行时变量,而不是立即数。(否则我们需要自修改代码。)对于orORMA相同(或存储器累加器; [P] |= A)。实际上减法(-)也是一样的;两个寄存器值之间也没有加/减,只有内部存储器。

## Preconditions: one value (x) in A, other value (y) pointed-to by DP
## post-condition: A = XOR of the inputs
## clobbers: P and 2 bytes at scratch_space.  DP unmodified

xor_A_DP:
  lp    scratch_space
  mvmd             # [P] = [DP]
  orma             # [P] |= A   # scratch_space[0] = x|y
  incp
  mvmd             # [P] = [DP]
  anma             # [P] &= A   # scratch_space[1] = x&y
  ldm              # A = [P]    # x&y
  decp
  sbm              # [P] -= A   # (x|y) - (x&y)
  ldm              # A = x^y

# rtn  if this is a function

字符串
注解重申了指令的作用,因为我以前从未使用过这个伊萨;它通常不是一个好的注解风格。(通常你想描述每条指令实现的更高级别的东西。)
阅读[DP]两次感觉很浪费,但“外部”内存并不慢(mvmd是1字节,3个周期,与RMW内部内存的指令相同),我认为避免它会花费更多的指令。除了film之外,没有一条指令可以执行[P] = A,它需要重复计数来填充内存,和exam交换。所以要复制,我想可以用exam; ldm来做,它比anma; orma稍微快一点。感觉很奇怪,ldm没有像std[DP] = A)那样的逆方向。
帕特里克实现(x+y) - 2*(x&y)的版本是21条指令(包括rtn和一些指针设置,用于将DP指向一个输入和一个DP输出,这是我已经假设的。(包括rtn)全部为单字节,但我认为这主要是由于选择使用2字节的内部内存作为临时空间,而不是1字节,而不是push/pop和exchanges,并在寄存器和已经设置的指针中获取输入。(计数字节或周期比指令更有用,但会花费更多精力。)
使用3周期SBM进行两次减法,或者在SBM之前使用SL指令进行左移,也可以提高帕特里克代码的效率和大小。(存储器范围内的BCD操作或16位加法/减法除外),所以我认为这两个表达式的最佳实现是相同的,除了(x+y) - 2*(x&y)多了一个sl。除非self-修改代码更好。
使用film(I=1),用A的副本填充2个字节的内存是有用的还是更好的?

lii   1                    # 2 bytes
  lp    scratch_space
  film            # [P++] = A twice  - for(d=I ; decrement d until it wraps)
  # P points past the end of 2 copies of the first input

  lp    scratch_space
  ldd             # A = [DP]   so A holds second input
  orma            # scratch_space[0] = x|y
  lp    scratch_space+1         # incp is also one byte and just as fast
  anma            # x&y
  ldm             # A = [P]      # A = x&y
  decp
  sbm             # [P] = (x|y) - (x&y)
  ldm
# rtn          # 13 total instructions including this


所以不,这很糟糕,lii 1是2字节,film比大多数都慢。

suzh9iv8

suzh9iv83#

按位OR也可以由以下操作代替

x ^ y = (x + y) - 2*(x & y)

字符串
如在此stackoverflow answer中针对类似问题所解释的。
下面是一个实现的代码示例(未测试):

org     &C030

            jp     start

start:      lp      B_REG           # point P to regB
            lidp    numX            # load x
            ldd                     #             A=x
            push
            exab                    # B=x         A=?
            lidl    <numY           # load y
            ldd                     # B=x         A=y
            anma                    # B=x&y       A=y
            ldm                     # B=x&y       A=x&y
            adm                     # B=2*x&y     A=x&y
            pop                     # B=2*x&y     A=x
            exab                    # B=x         A=2*x&y
            push
            ldd                     # B=x         A=y
            adm                     # B=x+y       A=y
            pop                     # B=x+y       A==2*x&y
            sbm                     # B=x+y-2*x&y A==2*x&y
            exab                    # B=2*x&y     A==x+y-2*x&y
            lidl    <numZ           # save result C
            std
end:        rtn

编辑:如果我使用Peter Cordes的回答的前提条件和风格,我的公式如下:

## Preconditions: one value (x) in A, other value (y) pointed-to by DP
## post-condition: A = XOR of the inputs
## clobbers: P and 2 bytes at scratch_space.  DP unmodified
xor_A_DP:
            lp    scratch_space
            mvmd             # [P] = [DP]
            adm              # [P] += A   # scratch_space[0] = x+y
            incp
            mvmd             # [P] = [DP]
            anma             # [P] &= A   # scratch_space[1] = x&y
            ldm              # A = [P]    # x&y
            decp   
            sbm              # [P] -= A   # (x+y) - (x&y)
            sbm              # [P] -= A   # (x+y) - 2*(x&y)
            ldm              # A = x^y

编辑2:夏普ESR-H SC 61860 µ-控制器的一个困难是它几乎没有文档记录。好的参考文献很少,而且往往不完整或包含错误。

我使用以下网站作为参考:

hrirmatl

hrirmatl4#

太棒了!谢谢,效果很好。

9 XOR 11 = 2

a XOR b = (NOT(a) AND b) OR (a AND NOT(b))
        = ((255-9) and 11) or (9 and (255-11))
        = (246 and 11) or (9 and 244)    
        = 2 or 0
        = 2

字符串
下面是使用8位寄存器的程序。要一起使用2个寄存器,如AND,您必须将P指向第二个寄存器。然后您可以[P]和A -> P:

##############################################################################
## xor.asm
## perform a logical XOR operation on numA and numB and store to numC
## numC = numA XOR numB
##############################################################################

                $JR
                org     &C030

                jp     start

I_REG           equ     0               # Internal Registers
J_REG           equ     1
A_REG           equ     2
B_REG           equ     3
XL_REG          equ     4
XH_REG          equ     5
YL_REG          equ     6
YH_REG          equ     7
K_REG           equ     8
L_REG           equ     9
M_REG           equ     10
N_REG           equ     11
PORTC           equ     95

numA:           db      9
numB:           db      11
numC:           db      0

# EXAB          A <-> B 
# SBM           [P] - A -> [P] 
# ANMA          [P] and A -> [P] 
# ORMA          [P] or A -> [P]
# PUSH          push A onto the stack
# POP           pop A from the stack

start:          lp      B_REG           # point P to the B register
                lidp    numA            # (not a & b)
                ldd                     # A = numA
                lib     255
                sbm                     # B = 255 - numA
                lidp    numB            # A = numB
                ldd
                anma                    # B = 255-numA & numB 
                exab                    # swap A and B to store result on the stack 
                push                    # push A (result) to the stack

                lidp    numB            # (a & not b)
                ldd
                lib     255
                sbm                     # B = 255 - numB, B = not b
                lidp    numA
                ldd
                anma                    # B = numA & (255 - numB)
                pop                     # grab the first result
                orma                    # B = final result
                lidp    numC
                exab
                std                     # numC = numA XOR numB

end:            rtn

相关问题