汇编 8086 中的顺序构造

Sequence construction in assembly 8086

我想做的是,从两个字节序列(我们称之为s1和s2)开始,我想获得序列d,代表每个位置的最大值。

我尝试将序列 s1 移动到目标中,以便之后我可以将序列 s2 与新的目标序列进行比较,并在需要时替换元素。

所以.. "movement" 完成了,只是它没有完成它的工作 - 它没有取代任何东西。

欢迎任何建议。 :D

;S1: 1, 3, 6, 2, 3, 7
;S2: 6, 3, 8, 1, 2, 5
;D: 6, 3, 8, 2, 3, 7

ASSUME cs:text_,ds:data_

data_ SEGMENT

s1 db '1362375'
l equ $-s1
s2 db '6381259' 
d db l dup (?)

data_ ENDS

text_ SEGMENT
start:
mov ax, data_
mov ds, ax
mov es, ax
mov si, offset s1
mov di, offset d
mov cx, l
cld
rep movsb
push si 
mov si, offset s2 
Repeta:
  cld
  lodsb
  repne scasb
  jg Instruct
  Instruct:
    stosb
loop Repeta
mov ax, 4c00h
int 21h
text_ ENDS
end start

您正在沉迷于使用 x86 字符串指令并将它们视为字符串。您要解决的问题与字符串无关。

您正在操作的字节数组是数字的 ASCII 码这一事实无关紧要或无用(除了 '0''9' 的 ASCII 码是连续且有序的, 所以你可以跳过将数字转换为整数的步骤)。

你需要解决的问题是一个简单的每元素最大值,像这样

for (unsigned i=0 ; i<size ; i++)
    d[i] = max(S1[i], S2[i]);

你的值(ASCII码)都小于127,所以你可以使用有符号或无符号比较,哪个更方便。

请注意,d[i] 的结果仅取决于 S1[i]S2[i],而不取决于任何字符串中任何较早或较晚的字节。一旦你意识到这一点,它应该很容易实现(你应该看到 repne scasb(字符串搜索,即 strchr)没有用)。

您可以独立于循环将一个数组复制到目标,但 x86 有足够的寄存器,这不是必需的,尤其是对于静态数据,因此您不需要在寄存器中保留 3 个指针,只需一个索引. (但是如果你愿意,你 可以 在寄存器中保留 3 个指针,使用 bxsidi)。只需从两个源中读取并将最大值存储到每次迭代中 d 中的正确位置,既简单又高效。 (您可以为此使用 stosb,如果愿意,可以使用 lodsb 从两个源数组之一加载。)

您当前的代码实际上接近工作(我认为),但使用 scasb 而不是 repne scasb。此外,scasbstosb 都会递增 di,因此您真正想要的是条件 mov [di-1], al。 (递增 di 的指令不能是有条件的。)此外,分支目标需要 您要跳过的指令之后。

循环内不需要 cld。在 rep movsb 之前做一次就好了。此外,使用调试器单步执行您的代码以获得循环的正确循环计数。


顺便说一句,在 SIMD 术语中,我们称之为 "vertical" 操作,而不是 "horizontal"(您必须在 16B 数据向量内随机播放,例如将相邻元素加在一起)。

另一个最近的问题询问了完全相同的问题,具有相同的数据,但具有 32 位代码。 My answer there shows how to use SSE2 pmaxub对两个16个无符号字节的向量并行做pairwise-max运算,然后将前6个字节的结果存入[d]。 8086 当然不支持 SSE2 指令,但 16 位实模式的现代 CPU 支持。