欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

8086指令系统中的串处理指令:一起来了解吧 [汇编篇]

最编程 2024-08-13 16:12:15
...
[汇编]8086指令系统---串处理指令 串处理指令处理存放在存储器中的字节串或字串,串处理的方向由方向标志位DF决定,串处理指令之前可加重复前缀,在执行串处理指令时,源串的指针SI和目的串的指针DI根据DF的指示自动增量(+1或+2)或自动减量(―1或―2)。  ⑴ 串处理指令
MOVSB / MOVSW 串传送
STOSB / STOSW 存串
LODSB / LODSW 取串
CMPSB / CMPSW 串比较
SCASB / SCASW 串扫描

  ⑵ 串重复前缀
REP  重复串操作
REPE / REPZ  相等/为零时重复
REPNE / REPNZ 不等/不为零时重复

  ⑶ 设置方向标志
CLD  使DF=0
STD  使DF=1  1 设置方向标志指令

CLD DF置0(clear direction flag)
STD DF置1(set direction flag)

为了处理连续存储单元中的字符串或数串,地址指针需要连续地增量或减量,指针增量或减量决定了串处理的方向。当用CLD指令使DF=0时,源串的指针SI和目的串的指针DI自动增量(+1或+2),当用STD指令使DF=1时,指针SI和DI自动减量(―1或―2)。地址指针是±1还是±2,取决于串操作数是字节还是字,处理字节串时,地址指针每次+1或―1,处理字串时,地址指针每次+2或―2。

  2 串处理指令

MOVSB / MOVSW 串传送(move string byte/word)
执行操作:
(ES:DI)←(DS:SI)
(SI)←(SI)±1(字节)或±2(字)
(DI)←(DI)±1(字节)或±2(字)

STOSB / STOSW 存串(load from string byte/word)
执行操作:
(ES:DI)←(AL)或(AX)
(DI)←(DI)±1(字节)或±2(字)

LODSB / LODSW 取串(store into string byte/word)
执行操作:
(AL)或(AX)←(DS:SI)
(SI)←(SI)±1(字节)或±2(字)

CMPSB / CMPSW 串比较(compare string byte/word)
执行操作:
(DS:SI)-(ES:DI),根据比较的结果设置条件码
(SI)←(SI)±1(字节)或±2(字)
(DI)←(DI)±1(字节)或±2(字)

SCASB / SCASW 串扫描(scan string byte/word)
执行操作:
(AL)-(ES:DI)或(AX)-(ES:DI),根据扫描比较的结果设置条件码
(DI)←(DI)±1(字节)或±2(字)

  这组串处理指令用于处理连续存储单元中的字操作数或字节操作数,它们有几个共同点:

1. 它们一般都分两步执行,第一步完成处理功能,如传送、存取、比较等。第二步进行指针修改,以指向下一个要处理的字节或字。

2. 源串必须在数据段中,目的串必须在附加段中,串处理指令隐含的寻址方式是SI和DI寄存器的间接寻址方式。源串允许使用段跨越前缀来指定段。

  3. 串处理的方向取决于方向标志DF,DF=0时,地址指针SI和DI增量(+1或+2);DF=1时,地址指针SI和DI减量(-1或-2)。程序员可以使用指令CLD和STD来建立方向标志。

4. MOVS、STOS、LODS指令不影响条件码,CMPS、SCAS指令根据比较的结果设置条件码。

与串传送指令MOVS和串存入指令STOS联用的重复前缀是REP,取串指令LODS一般不加重复前缀。与串比较指令和串扫描指令联用的重复前缀是REPE(REPZ)或REPNE(REPNZ)。


  3 串重复前缀

REP 重复执行串指令,(CX)=重复次数
执行操作:
① (CX)=0时,串指令执行完毕,否则执行② ~ ④
② (CX)←(CX)-1
③ 执行串指令(MOVS或STOS)
④ 重复执行①

REPE / REPZ 相等/为零时重复执行串指令,(CX)=比较/扫描的次数
执行操作:
① (CX)=0或ZF=0时,结束执行串指令,否则继续② ~ ④
② (CX)←(CX)-1
③ 执行串指令(CMPS或SCAS)
④ 重复执行①

REPNE / REPNZ 不等/不为零时重复执行串指令,(CX)=比较/扫描的次数
执行操作:
① (CX)=0或ZF=1,结束执行串指令,否则继续② ~ ④
② (CX)←(CX)-1
③ 执行串指令(CMPS或SCAS)
④ 重复执行①

REP对其后的串指令(MOVS或STOS)只有一个结束条件,即重复次数(CX)=0。在进行串比较和串扫描时,串指令前应加前缀REPE(REPZ)或REPNE(REPNZ),这两条重复前缀用重复次数(CX)和比较结果(ZF)来控制串指令的结束。当(CX)=0时,说明每个串数据都比较(或扫描)过了,此时串操作正常结束;当因ZF=1或0而结束串操作时,说明在满足比较结果相等或不等的条件下,可提前结束串操作。

例 编写程序,传输20字节的字符串。

 DATSEG  SEGMENT
  DATAX   DB 'ABCDEFGHIJKLMNOPQRST'
  DATAY   DB 20 DUP(?)
  DATSEG  ENDS
  ; - - - - - - - - - - - - - - - - - - - -
  CODSEG  SEGMENT
  ASSUME  CS:CODSEG,DS:DATSEG,ES:DATSEG
START: MOV AX,DATSEG
  MOV DS,AX  ; initialize the data segment
  MOV ES,AX  ; initialize the extra segment
  CLD ; clear direction flag for autoincrement
  MOV SI,OFFSET DATAX  ; load the source pointer
  MOV DI,OFFSET DATAY  ; load the destination pointer
  MOV CX,20  ; load the counter
  REP MOVSB  ; repeat until CX becomes zero
  MOV AX,4C00H; return to DOS
  INT 21H
CODSEG ENDS
  END START

串传送指令将SI所指示的数据段中的数据传送到由DI指示的附加段中,本例将源串和目的串都设置在同一个段DATSEG中,因此,DS和ES都定义为DATSEG。

例 编写程序:
(1)用STOS指令将0AAH存入100个存储器字节;
(2)利用LODS指令测试这些存储器单元的内容是否是0AAH,如果不是则显示"bad memory"。

  DTSEG  SEGMENT
  DATAM  DB 100 DUP(?)
  MESG   DB 'bad memory', '$'
  DTSEG  ENDS
  ; - - - - - - - - - - - - - - - - - -
  CDSEG  SEGMENT
  ASSUME CS:CDSEG,DS:DTSEG,ES:DTSEG
START: MOV AX,DTSEG ; initialize
  MOV DS,AX; DS register
  MOV ES,AX; and ES register
  CLD ; clear DF for increment
  MOV CX,50; load the counter(50 words)
  MOV DI,OFFSET DATAM ; load the pointer for destination
  MOV AX,0AAAAH   ; load the pattern
  REP STOSW; repeat until CX=0
  ; bring in the pattern and test it one by one
  MOV SI,OFFSET DATAM  ; load the pointer for source
  MOV CX,100   ; load the counter(100 bytes)
AGAIN: LODSB ; load into AL from DS:SI
  XOR AL,0AAH  ; is pattern the same?
  JNZ OVER ; if not the same, then exit
  LOOPAGAIN ; continue until CX=0
  JMP EXIT ; exit program
OVER: MOV AH,09 ; display
  MOV DX,OFFSET MESG   ; the message
  INT 21H  ; routine
EXIT: MOV AX,4C00H ; return to DOS
  INT 21H
  CDSEG  ENDS
  END START

把0AAH存入100个字节是通过执行50次的字操作来完成的。在测试部分,LODSB指令把存储器字节的内容取到AL,并和数据0AAH异或,如果这两个数相同,ZF=1,则继续进行下一个数的测试。如果两数不同,则ZF=0,转去执行显示字符串的BIOS功能调用。显示字符串用了三条指令,首先在AH中装入的显示字符串的功能号09,然后在DX中装入字符串的地址,再用INT 21H调用BIOS例程,完成显示指定字符串的功能。

例 假设有人将电子字典中的"LABEL"误拼为"LABLE",编写程序比较这两个词,并根据比较结果显示
  (1)如果相同,则显示"The spelling is correct";
  (2)如果不同,则显示"Wrong splling"。

 DATASEG SEGMENT
  DAT_DICT DB 'LABEL'
  DAT_TYPE DB 'LABLE'
  MESS1 DB 'The spelling is correct ','$'
  MESS2 DB 'Wrong spelling ','$'
 DATASEG ENDS
; - - - - - - - - - - - - - - - - - - - - -
CODESEG SEGMENT
ASSUME CS:CODESEG,DS:DATASEG,ES:DATASEG
 START: MOV  AX,DATASEG
MOV  DS,AX ; initialize the data segment
MOV  ES,AX ; initialize the extra segment
CLD ; DF=0 for autoincrement
MOV  SI,OFFSET DAT_DICT ; SI is source pointer
MOV  DI,OFFSET DAT_TYPE ; DI is destination pointer
MOV  CX,05 ; load the counter
REPE CMPSB ; repeat as long as equal or until CX=0
JEOVER ; if ZF=1 then display mess1
MOV  DX,OFFSET MESS2 ; if ZF=0 then display mess2
JMP  DISP
  OVER: MOV  DX,OFFSET MESS1
  DISP: MOV  AH,09 ; display message
INT  21H
MOV  AX,4C00H ; return to DOS
INT  21H
 CODSEG ENDS
END START

用CMPSB指令可将两个串中的字符逐一比较,在比较SI和DI指向的第一对字符时,根据比较结果设置ZF并使(SI)+1,(DI)+1以及(CX)-1。因为第一对字符是相同的('L'),所以ZF=1,于是由REPE控制再重复比较下一对字符。直到比较第四对字符'E'和'L'时,由于它们不相同,ZF设置为0,所以串比较结束。打印的信息应是:'Wrong spelling '。

例 编写程序,将姓名中的HU DAMING(胡大明)修改为HU DANING(胡大宁),并显示出正确的姓名。

DATA SEGMENT
NAME DB 'HU DAMING', '$'
DATA ENDS
; - - - - - - - - - - - -
CODE  SEGMENT
ASSUME CS:CODE,DS:DATA,ES:DATA
START: MOV   AX,DATA
MOVDS,AX  ; initialize the data segment
MOVES,AX  ; initialize the extra segment
CLD   ; DF=0 for autoincrement
MOV   AL,'M'
MOV   DI,OFFSET NAME ; DI is destination pointer
MOVCX,09  ; load the counter
REPNE SCASB  ; repeat as long as equal or until CX=0
JNEDISP; if ZF=0 then display name
DECDI ; decrement to point at 'M'
MOVBYTE PTR [DI],'N' ; replace 'M' with 'N'
 DISP: MOVAH,09  ; display the corrected name
MOVDX,OFFSET NAME
INT21H
MOVAX,4C00H   ; return to DOS
INT21H
CODE  ENDS
ENDSTART

本例中,AL寄存器中的字符'M'与NAME中的每个字符进行比较,如果串中字符与'M'不同,则DI增量,CX减量,继续进行下一个字符的扫描比较,一直到发现'M'或CX=0为止。在本例中,因为发现了'M',比较的结果使ZF=1,同时DI已指向了下一个字符'I',所以DI退回一个字符位置(DEC DI),并用N取代M。