ASM86 má velmi silný nástroj v řetězcových instrukcích. Za řetězec je zde na rozdíl od Pascalovského považován blok dat v paměti o téměř libovolné délce (podle definice jsme omezeni jen velikostí segmentu, to se ale dá snadno obejít). Pro použití řetězcových instrukcí jsou vyčleněny dvojice registrů, které nesou adresy:
V praxi to znamená, že vždy jeden blok v paměti je označen za zdrojový, druhý za cílový. Důležitou roli zde hrají i registry:
Řetězové instrukce pak jsou
Slovo zvýšit v těchto popisech činnosti nahradíme slovem snížit při DF = 1. Tyto instrukce umožní najednou provést určitou činnost a přitom aktualizují adresy podle stavu DF a podle toho, jestli pracujeme se slabikami nebo slovy.
Následující příklad využívá přímého zápisu do videopaměti (VRAM) v textovém režimu VGA k výstupu pascalovského řetězce. VRAM, začíná na adrese $B8000. Je organizovaná jako pole slov nesoucích informace o zobrazovaných znacích. Každé slovo nese slabiku atributů (barva znaku a jeho pozadí) a slabiku s ASCII kódem zobrazeného znaku. 80 slov VRAM je jeden řádek na obrazovce. Proto při zvýšení adresy $B8000 o 160 můžeme pracovat s druhým řádkem atd.
Příklad:
var slovo:string;
begin
slovo:='Ahoj';
asm
PUSH
DS
{ulož obsah DS do zásobníku, budeme ho měnit}
JMP
@dal
{obejdi data}
@vram:
DW
$0000,$B800
{offset:segment VRAM, Pozor! je to obráceně}
@adsl:
DD
slovo {adresa slova, ukazatel na něj}
@dal: {začátek programu}
LDS
SI,CS:[
OFFSET
@adsl] {DS:SI nasměruj na zdroj (na slovo)}
LES
DI,CS:[
OFFSET
@vram] {ES:DI nesměruj na VRAM}
XOR
CH,CH
{nuluj CH}
MOV
CL,[SI]
{do CL dej délku řetězce slovo, 1. slabiku}
INC
SI
{posuň se za slabiku s délkou}
MOV
AH,$6F
{do AH dej atributy nápisu}
@cyk: {cyklus pro znak po znaku}
LODSB
{naber kód znaku z řetězce do AL a zvyš
SI+1}
STOSW
{ulož obsah AX do VRAM, zvyš DI+2}
LOOP
@cyk
{sniž CX o jednu, není-li nula jdi na @cyk}
POP
DS
{vrať registr DS do původního stavu}
end;
end.
Uvedený program změní slabiku na slovo v registru AX s tím, že bude kód znaku doplněn o atributy. Jestliže změníme hodnotu v AH ovlivníme tím barvu výstupu.
Dosud známe jen prefix přeskočení. Prefix opakování se používá před řetězcovými instrukcemi a umožňuje tak jejich podmíněné i nepodmíněné opakování. Jejich použitím zrychlíme a zjednodušíme program. Nepodmíněným prefixem je
Tento prefix píšeme většinou před instrukci MOVSB (MOVSW). Jestliže máme nastavený registr CX na počet prvků řetězce a adresové registry zdrojového a cílového řetězce, zajistí REP jejich zkopírování na jednom řádku programu (např. REP MOVSB).
Příklad:
var slovo1,slovo2:string;
begin
slovo1:='Ahoj';
asm
PUSH
DS
{ulož do zásobníku obsah DS, změníme ho}
JMP
@dal
{skoč na začátek, obejdi data}
@adr:
DD
slovo1,slovo2
{definice ukazatelů na pole}
@dal:
LDS
SI,CS:[
OFFSET
@adr] {naber adresu zdrojového řetězce}
LES
DI,CS:[
OFFSET
@adr+4] {naber adresu cílového řetězce}
XOR
CH,CH
{nuluj CH}
MOV
CL,[SI]
{do CL dej délku řetězce}
INC
CX
{pascalovský řetězec
nese o slabiku více}
REP
MOVSB
{kopíruj řetězce po
slabikách}
POP
DS
{vrať obsah DS ze
zásobníku}
end;
writeln (slovo1,' ',slovo2);
readln;
end.
V příkladu kopírujeme jen tolik prvků, kolik má zdrojové slovo slabik. Tuto informaci si zjistíme z první slabiky proměnné slovo1. K tomu musíme ještě přičíst 1, protože pascalovský řetězec nese navíc informaci o délce. I když veškeré přesuny se odehrávají v datovém segmentu s adresou v DS, je dobré si zvyknout na to, že vždy, když měníme DS, ukládáme jeho obsah pro jistotu do zásobníku.
Řetězcové instrukce vyhledání a porovnání využívají registr příznaků ZF. Proto ASM86 obsahuje navíc prefixy podmíněného opakování:
Příklad:
uses crt;
var pole:array [0..9] of word;
hledany,pozice:word;
i:byte;
begin
clrscr;
randomize;
for i:=0 to 9 do
pole[i]:=random(65535); {do pole náhodná čísla}
hledany:=pole[random(10)]; {vyber hledané číslo}
writeln ('Hledam:',hledany);
asm
JMP
@zac
{skok na začátek}
@adr:
DD
pole
{definice ukazatele na pole}
@zac:
MOV
AX,hledany
{do AX vlož hledané číslo}
MOV
CX,10
{do CX vlož délku řetězce
(pole)}
LES
DI,CS:[
OFFSET
@adr] {naber adresu řetězce}
REPNE
SCASW
{opakuj do shody porovnání}
MOV
pozice,9
{spočítej kolikátý je hledaný,}
SUB
pozice,CX
{k tomu použiješ to, co zbylo v CX}
end;
for i:=0 to 9 do
begin
if i<>pozice then textcolor(15) else textcolor(12);
writeln (pole[i]);
end;
readkey;
end.
Tento program vyhledá slovo v poli. K tomu slouží jen řádek REPNE SCASW. Ten opakuje pohyb po poli, dokud nenajde shodu s hodnotou v registru AX (ta se projeví nastavením ZF do 1) . K zjištění pozice hledaného dobře poslouží zbytek v registru CX. Kdyby byl zbytek nulový, hledaný prvek by v poli nebyl.
Příklad:
uses crt;
var slovo1,slovo2:string;
ukazatel:pointer;
i,misto,delka:word;
begin
slovo1:='Nazdar programátoři! '+
'Zkuste vyhledat nějaké slovo z této
věty.';
slovo2:='slovo';
delka:=length(slovo2);
asm
PUSH
DS {ulož DS, budeme ho měnit}
JMP
@dal
{přeskoč data}
@ukp:
DD
slovo1,slovo2
{ukazatele na řetězce}
@dal:
LDS
SI,CS:[
OFFSET
@ukp] {naber adresu zdroje}
INC
SI
{přeskoč délku řetězce}
@cyk:
LES
DI,CS:[
OFFSET
@ukp+4]{naber adresu cíle, hledaného slova}
INC
DI
{přeskoč slabiku s délkou
řetězce}
MOV
CX,delka
{do CX vlož délku řetězce}
REPE
CMPSB
{opakuj do neshody (konce
hledaného)}
JZ
@konec
{byla shoda tak na konec}
SUB
SI,delka
{nebyla shoda tak se v SI vrať}
INC
SI
ADD
SI,CX
{k návratu v SI použij zbytek v
CX}
JMP
@cyk
{a znovu hledat}
@konec:
POP
DS
{vrať obsah DS, už ho
nebudeme měnit}
MOV
misto,SI
{vypočítej místo v prohledávaném}
MOV
SI,CS:[
OFFSET
@ukp] {k tomu použiješ délku řetězce zdroje}
ADD
SI,delka
{délku cíle, tedy hledaného}
SUB
misto,SI
end;
clrscr;
for i:=1 to length(slovo1) do
begin
if not(i in [misto..misto+delka-1]) then
textcolor (15)
else
textcolor(12);
write(slovo1[i]);
end;
readkey;
end.
V příkladu prohledáváme řetězec slovo1. Hledáme v něm umístění podřetězce slovo2. Program má dva cykly v sobě. První zajišťuje pohyb po prohledávaném řetězci v případě neshody (je realizován JMP). Druhý vnitřní zajišťuje pohyb po prohledávaném s kontrolou s hledaným (je realizován REPE). V případě shody je po cyklu REPE v registru ZF = 1 (prostě nevyskočil neshodou ale nulou v CX=> konec hledaného slova a shoda). Proto cyklus prohledávání ukončíme podmíněným skokem JZ na konec. Zde ze zjistí adresa v prohledávaném řetězci. To je ale adresa za posledním znakem shody. Proto se vrátíme nazpátek o délku slova (tam je hledané slovo).