Assembly 如何有效地在8080上进行签名比较?
我想比较两个16位数字并在结果上进行分支:相当于8085上的if(a有两个用于有符号比较和有符号溢出,以及用于在有符号小于/大于时跳转的未记录指令JK/JNKAssembly 如何有效地在8080上进行签名比较?,assembly,comparison,signed,intel-8080,Assembly,Comparison,Signed,Intel 8080,我想比较两个16位数字并在结果上进行分支:相当于8085上的if(a有两个用于有符号比较和有符号溢出,以及用于在有符号小于/大于时跳转的未记录指令JK/JNK 不确定8080上是否有。但是如果没有,你可以通过切换顶部位 bool signedCmp(int a, int b) { return unsignedCmp(a ^ INT_MIN, b ^ INT_MIN); } 我不知道8080的组装,但也许像这样的东西可以用来比较DE和HL mov a, e sub a, l
bool signedCmp(int a, int b)
{
return unsignedCmp(a ^ INT_MIN, b ^ INT_MIN);
}
我不知道8080的组装,但也许像这样的东西可以用来比较DE和HL
mov a, e
sub a, l ; e - l
mov a, h
xri a, 0x80
mov h, a ; h ^= 0x80
mov a, d
xri a, 0x80 ; a = d ^ 0x80
sbb a, h ; d - h
jc lessthan ; branch on carry
; >= case
:lessthan
; < case
mova,e
子a,l;e-l
mov a,h
xri a,0x80
mov h,a;h^=0x80
莫夫a,d
xri a,0x80;a=d^0x80
sbb a,h;d-h
jc lessthan;分公司结转
例
:lessthan
例
考虑到公认的答案及其评论,我会重新考虑杰斯特的建议(在我看来,与建议的Z80代码相比,这似乎仅为+4B,但代码布局有所不同,即更少/更大的_相等分支所在的位置,这可能会进一步复杂化或简化您的代码……此外,它应该比每次对D和H执行xor 0x80更好):
针对任何16b#XY常量的reg对:
; signed 16b compare RP (HL/DE/BC) vs nonzero constant #XY
; subroutine, returns CF=1 if RP < #XY, modifies A
mov a,R
xri 0x80 ; convert 8000..7FFF into 0000..FFFF
cpi #X^0x80 ; "X" is xor-ed with 0x80 too to have it in 0000..FFFF range
rnz ; if ZF=0, then CF=1 is (RP < XY) and CF=0 is (RP > XY)
; R == X, the low 8b P vs Y will decide
mov a,P
cpi #Y ; CF=1 if (RP < XY)
ret ; 10B for particular #XY constant and RP
; inlined form
mov a,R
xri 0x80 ; convert 8000..7FFF into 0000..FFFF
cpi #X^0x80 ; "X" is xor-ed with 0x80 too to have it in 0000..FFFF range
jnz HiByteWasDecisive ; if ZF=0, then CF is set correctly, done
mov a,P ; R == #X, the low 8b P vs #Y will decide final CF
cpi #Y ; CF=1 if (RP < #XY)
:HiByteWasDecisive
; CF=1 is (RP < #XY) and CF=0 is (RP >= #XY)
...
;符号16b比较RP(HL/DE/BC)与非零常数#XY
;子例程,如果RP<#XY修改了
莫夫a,R
xri 0x80;将8000..7FFF转换为0000..FFFF
cpi#X^0x80;“X”也与0x80异或,以使其在0000..FFFF范围内
rnz;如果ZF=0,则CF=1为(RPXY)
;R==X,低8b P vs Y将决定
莫夫a,P
cpi#Y;CF=1如果(RP=#XY)
...
如果所有其他操作都失败,您可以检查操作数是否具有相同的符号。如果没有,您已经知道哪个符号更大。如果是,那么使用减法是安全的。我可以快速看一眼,这也是sdcc
生成的内容。改用无符号值如何?没有机会将其他代码中的所有内容偏移+0x8000并在0..ffff范围内操作?我是一个编译器后端。我无法决定int是否已签名!@DavidGiven这在技术上是不正确的。您正在为某种抽象机器(如C抽象机器)创建实现,只要实现“好像”使用有符号整数是正确的,即使实际实现是使用无符号本机类型。现在将其付诸实践可能与现代clang/gcc编译器使用自动矢量化/etc所做的类似(比如用压缩整数并行化替换循环中的朴素“int”)。也就是说,显然不值得为晦涩难懂的8b平台付出多少努力……所以你几乎是正确的。:)挑剔:小于的倒数是大于或等于,而不仅仅是“更大”。遗憾的是,8080上没有这些标志。但切换顶部看起来很容易,我会尝试一下(虽然我的寄存器有点用完了)。事实上,这是可行的——但每次比较都需要额外的8个字节[悲伤的脸]:mov a,d;xri 0x80;mov d,a;mov a,h;xro 0x80;mov h,a
。当与常数进行比较时,我可以将xor滚动到立即值中,但由于xri
重置进位标志,我无法按照您上面建议的方式内联执行(它会导致sbb
出错)8080上的@PeterCordesjp
是8086上的jns
如同“跳转正/正”,那么就有“jm”如同“跳转负”…奇偶校验跳跃是jpo/jpe
:但如果有8080汇编程序具有这些助记符的特定变体,我不会感到震惊,我不是8080人,但在Z80的世界中,甚至有一些命名(非官方)指令的冲突方式,如sll
被一些汇编程序用作sla
的别名(左移算术=左移逻辑),一些汇编程序会将sll
汇编为非官方的sl1/sli/sls/…
=shift left+b0=1。我的意思是,也许我使用的TXT使用的是非官方的助记符,jns
它甚至是官方的8080,这就是为什么我在这里放了注释,解释我想到的是哪一个,它应该在SF=0时跳转(当SF=1时,rm
应ret
)。啊,谢谢,我误解了他们的意思。这些是一些令人困惑的助记符,特别是当Z80将奇偶校验标志重新定义为带符号溢出时,人们将其与符号标志一起使用以进行比较。@PeterCordes Z80实际上也将该标志用作奇偶校验,并且还用于第三个目的,我已经忘记了,它是signed overflow仅适用于特定的指令…:D…非常有趣;)(现在就开始玩弄ZX Spectrum,所以我最近遇到了所有这些Z80细微差别:))所以我现在有15个字节用于与寄存器进行比较,13个字节用于与常量进行比较;与助手例程进行比较时,与寄存器进行比较的字节数将为6个(3个用于例程,3个用于测试)和9个字节用于与常量进行比较(另外3个用于加载值)。但是如果必须将值强制到我目前没有的特定寄存器中,也会受到惩罚。我的意思是,这样更好,我也会这样做,但我希望有更多更好的。。。
mov a,d
xra h
jp sameSigns ; as "JNS" in 8086 / "jp p," in Z80
; sign bits are different, signed overflow may happen
; but if H positive, then DE is less than HL
xra d ; make A=H and set sign flag
jm DeIsGreaterEqualThanHl
:DeIsLessThanHl
; DE < HL
...
:sameSigns
; sign bits are equal, it is safe to do ordinary sub
mov a,e
sub l
mov a,d
sbb h
jc DeIsLessThanHl
:DeIsGreaterEqualThanHl
; DE >= HL
...
:SignedCmpDeHl
mov a,d
xra h
jp sameSigns ; as "JNS" in 8086 / "jp p," in Z80
; sign bits are different, signed overflow may happen
; but if H positive, then DE is less than HL
xra d ; make A=H and set sign flag (CF=0)
rm ; return CF=0 when DE >= HL (H is negative)
stc
ret ; return CF=1 when DE < HL (H is positive/zero)
:sameSigns
; sign bits are equal, it is safe to do ordinary sub
mov a,e
sub l
mov a,d
sbb h
ret ; return with CF=1 when DE < HL (CF=0 DE >= HL)
; signed compare 8b or 16b register vs 0, into SF, destroys A
xra a ; A=0
ora R ; 16b R=[HDB], or any 8b R: SF = (RP < 0 or R < 0)
...i.e. "jm hlIsLessThanZero"
; signed compare 8b or 16b register vs 0, into CF, destroys A
mov a,R ; 16b R=[HDB], or any 8b R
ral ; CF = (RP < 0) or (R < 0)
...i.e. "jc hlIsLessThanZero" or "sbb a" to get 0/255
; signed 16b compare RP (HL/DE/BC) vs nonzero constant #XY
; subroutine, returns CF=1 if RP < #XY, modifies A
mov a,R
xri 0x80 ; convert 8000..7FFF into 0000..FFFF
cpi #X^0x80 ; "X" is xor-ed with 0x80 too to have it in 0000..FFFF range
rnz ; if ZF=0, then CF=1 is (RP < XY) and CF=0 is (RP > XY)
; R == X, the low 8b P vs Y will decide
mov a,P
cpi #Y ; CF=1 if (RP < XY)
ret ; 10B for particular #XY constant and RP
; inlined form
mov a,R
xri 0x80 ; convert 8000..7FFF into 0000..FFFF
cpi #X^0x80 ; "X" is xor-ed with 0x80 too to have it in 0000..FFFF range
jnz HiByteWasDecisive ; if ZF=0, then CF is set correctly, done
mov a,P ; R == #X, the low 8b P vs #Y will decide final CF
cpi #Y ; CF=1 if (RP < #XY)
:HiByteWasDecisive
; CF=1 is (RP < #XY) and CF=0 is (RP >= #XY)
...