Индексті айнымалыны ұйымдастыру

Массивтермен жұмыста туатын келесі сұрақ – массивтің элементтеріне қалай қатынауға болады, индексті айнымалылар қалай ұйымдастырылады. Бұл сұрақтарға жауап беру үшін алдымен компьютердің адресті модификациялау тәрізді ерекшелігімен танысу қажет.

Адресті модификациялау.Бұған дейін операндтар үшін жадтың нақтылы адрестері (атаулары) көрсетілетін командалар қарастырылды, мысалы: MOV CX,A. Бірақта жалпы жағдайда командада адреспен бірге тік жақшада қандай да бір регистр көрсетілуі мүмкін, мысалы: MOV CX,A[BX]. Онда команда көрсетілген А адресімен емес, орындалатын адрес деп аталатын адреспен (Аорн) жұмыс жасайды. Мұнда ол адрес келесі формуламен есептеледі:

Аорн= (А+[BX]) mod 216,

мұнда [BX] ВХ регистірінің құрамы дегенді білдіреді. Басқаша айтқанда орталық процессор команданы орындамас бұрын А адресіне ВХ регистіріндегі мәнді қосады да, қандай да жаңа адрес алады, міне осы адрестен екінші операнд алынады. (Команда өзгермейді адресті есептеу процессордың ішінде жасалады.) Егер қосу нәтижесінде шамадан артық қосынды шықса, онда оның соңғы 16 орны алынады, оны формуладағы mod амалынан көреміз.

Командадағы адресті орындалатын адреске ауыстыру адресті модификациалау деп аталады, ал модификациалауда қолданылатын регистрді регистр-модификатор немесе жай ғана модификатор дейміз. Мұнда, модификатор ретінде кез келген регистрді ала беруге болмайды, мысалы, Intil тобы микропроцессорларында ЕBX/BX,ЕBP/BP,ESI/SI және EDI/DI регистрлерінің бірі ғана алынады.

Мысалға, ADD A[SI],5 командасын алайық. Мұнда модификатор ретінде регистр SI алынған. Онда қазір 100 саны тұр делік. Олай болса Аорн= А+[SI]=А+100, бұл командада 5 саны А адресті емес А+100 адресті ұяшықтағы санға қосылатын болады. Егер де SI-де -2(0FFFFh) саны тұрса, онда Аорн= А-2, сондықтан 5 саны А-2 адресті ұяшықтағы санға қосылатын болады.

Мысалдан бір команданың өзі әр түрлі адрестермен орындала алатынын көреміз. Бұл өте маңызды, осы үшін адрестерді модификациялау жасалады. Адрестерді модификациялаудың пайдалы болу жағдайларының бірі, индексті айнымалыларды ұйымдастыруда қолданылатын, индекстеу болып табылады.

Индекстеу.Келесі мысалды қарастырайық: айталық

X DW 100 DUP(?) ;X[0..99]

массиві берілсін, массивтің элементтерінің қосындысын АX регистріне жазу керек.

Қосындыны табу үшін, алдымен АХ-ке 0 жазу керек, содан соң мына амалды AX:=AX+X[i], мұнда і 0-ден 99-ға дейін өзгереді, орындау керек. Х[i] элементінің адресі х+2*і болғандықтан, оған сәйкес команда мынандай болуы тиісті:

АDD AX, X+2*i

Бірақ мұндай команда машиналық тілдің және Ассемблер тілінің ережелеріне қайшы келеді: командада оның барлық бөліктері, оның ішінде адресі, бекітілген болып, өзгермеуі керек. Ал, мұнда і индексінің өзгеруімен бірге адрес өзгеріп отырады.

Сонымен келесі проблемаға тап болдық: алгоритм бойынша команда әртүрлі адрестермен жұмыс істеуі керек (өзгеретін адрестермен жұмыс істейді), ал машиналық тілде тек бекітілген адрес болуы қажет. Міне осы қайшылықты болдырмау үшін, есептеуіш машиналарында адресті модификациялау енгізілген.

Х+2*і өзгеретін адресті екі қосылғышқа бөлеміз: і индексінен тәуелді емес тұрақты қосылғыш Х-ке және индекстен тәуелді қосылғыш 2*і-ге. Тұрақты қосылғышты команданың өзіне жазамыз, ал айнымалы қосылғышты қандай да бір регистр-модификаторға (айталық SI-ге) жазамыз да осы регистрді командада модификатор ретінде қолданамыз:

Не шықты? Мұнда команданың жазылу түрі өзгермейді, яғни машиналық тілдің ережелерін қанағаттандырады. Екінші жағынан, команда орындалатын адреспен ж ұмыс жасайды, ал ол командадағы Х адресімен SI регіистрінің құрамы (2*і)-дің қосындысынан шығады. Сондықтан біз SI –дің мәнін өзгерте отырып, өзгермейтін команданы әртүрлі адрестермен жұмыс жасатамыз. Сөйтіп, машиналық тілдің де, алгоритмінің де талаптарын қанағаттандырамыз. Ендігі қалғаны тек SI регистрінің құрамын дұрыс өзгерту. Ол былай орындалады: алдымен SI-ге 0 жазылады, содан соң оның мәні 2 қадамға артып отырады; нәтижесінде біздің командамыз Х,Х+2, Х+4,...,Х+198 адрестерімен жұмыс жасайды.

Регистр-модификатор индексті сақтауға қолданылатындықтан (дәлірек айтқанда – индекстен тәуелді өрнек), ондай регистр - индекстік регистр, ал индексті айнымалының адресін алуды сипаттау әдісі - идекстеу деп аталады.

Осы айтылғандарды ескере отырып, Х массивінің элементтерінің қосындысын табу программасының фрагменті төмендегідей болады:

MOV AX,0 ;қосындының бастапқы мәні AX:=0

MOV CX,100 ;цикл санағышы СХ:=100

MOV SI,0 ;индекстің бастапқы мәні

L: ADD AX,X[SI] ;AX:=AX+X[I]

ADD SI,2 ;келесі индекс

LOOP L ;100 рет цикл қайталануы

Жанама сілтемелер. Адресті модификациялауды пайдаланудың тағы бір жағдайын қарастырайық.

Айталық бізге келесі есепті шешу қажет болсын: адресі белгілі емес, бірақ ол адрес ВХ регистріне жазылған сөз өлшемді қандай да бір ұяшық бар болсын, осы ұяшыққа бір санды (мысалы 300 санын) жазу керек

Егер ол ұйяшықтың адресі (Х) алдын ала белгілі болса, онда бұл есеп MOV x, 300 командасымен шешіледі. Бірақ программаны құру сәтінде біз ол адресті білмейміз, сол себепті командада оны көрсете алмаймыз. Не істеу керек? Команданың орындалатын адреспен жұмыс істейтінін еске түсірейік, сондықтан қосындысында осы бізге белгісіз адресті беретіндей адрес және модификатор алу қажет. Біздің жағдайымызда нөлінші адресті және ВХ регистрін алу қажет, онда Аорын=0+[BX]=0+x=x. Сондықтан біздің есебіміз

MOV [BX], 300

командасымен шешіледі.

Мұндағы қолданылатын адресті модификациялау тәсілінің ерекшелігі: біз адресті екі қосылғыштың қосындысы арқылы кескіндейміз оның бірі командаға жазылады, ал екіншісі регистрге жазылады, бірақ бұрын екі қосылғышта нөлден өзгеше болатын, енді командаға жазылатын бір қосылғыш нөл, сондықтан адрес тұтасымен регистрге «жасырылған». Командада біз адрес тұрған орынды (регистрді) ғана көрсетеді екенбіз. Мұндай адресті аралық байланыс арқылы көрсету тәсілі жанама сілтеме немесе жанама адрестеу деп аталады.

Жанама сілтемеде, әдетте, ол көрсететін ұяшықтың өлшемін анықтау қажет болатындығын айта кетелік. Егер, мысал үшін, адресі ВХ регистрінде тұрған ұяшыққа нөлді жазу қажет болса, онда ол үшін MOV [BX],0 командасын қолдануға болмайды, бұл командада операндтардың өлшемі түсініксіз: 0 байт та, сөз де бола алады, ВХ адресі де байттық та, сөздік те адрес бола алады (жоғарыда келтірілген мысалды мұндай жағдай болмады, себебі 300 саны тек сөз өлшемді бола алады). Сондықтан РТR операторының көмегімен, операндалардың өлшемін көрсету қажет:

MOV BYTE PTR [BX],0 ;байтты орналастыру

MOV WORD PTR [BX],0 ;сөзді орналастыру

Бірнеше регистр бойынша модификациялау. Адресті модификациялау бір регистр модификатор бойынша жүргізілетін жағдайды қарастырдық. Модификациялау идеясын бірнеше модификаторларды қолдануға жеңіл жалпылауға да болады. Ол үшін командада адреспен бірге бірнеше осындай регистрлер көрсету керек. ДК-де бірден екі модификатор көрсетуге рұқсат берілген, оның біреуі міндетті түрде ЕBX/BX немесе ЕBP/BP регистрлерінің бірі, ал екіншісі ESI/SI немесе EDI/DI регистрлерінің біреуі болуы қажет (ЕBX/BX және ЕBP/BP немесе ESI/SI және EDI/DI ережесін қолдануға боламайды). Мысалы:

MOV АХ,А[BX][SI]

Бұл жағдайда орындалатын адрес, келесі формуламен есептеледі:

Аорын = (A+[BX]+[SI]) mod 2 16

Екі регистр бойынша модификациялау әдетте екі өлшемді массивтермен жұмыста қолданылады. Айталық, мысал үшін, 10×20 ретті А матрицасы берілсін:

A DB 10 DUP (20 DUP(?)) ;A [0..9,0..19].

Ассемблер тілінде модификацияланатын адрестерді жазу. Ассемблер тілінде модификацияланатын адрестерді жазу ережелерін нақтылайық. Айталық А адресі өрнектерді білдірсін, ал Е кез келген өрнек (адрестік немесе тұрақтылық), онда ассемблер тілінде командада адрестердің жазылу формасының келесі үш түрін қолдануға болады

A: Aорн=A

E[M]: Aорн=(E+[M]) mod 216 (M: BX,BP,SI,DI)

E[M1][M2]: Aорн=(E+[M1]+[M2]) mod 216 (M1:BX,BP;M2:SI,DI)

(Ескерту. Егер Е=0 болса, онда 0-ді жазбауға болады: 0[M]=[M])

Тағыда айта кетейік, ДК-де регистр-модификатор ретінде тек қана ВХ,ВР,SІ немесе DI регистрлерін пайдалануға болады. Бір регистр бойынша модификациялауда ғана, осы төрт регистр қолданылады. Ал екі регистр бойынша модификациялауда регистр-модификаторлардың кез келген жұбын қолдануға рұқсат етілмеген, бір регистр ВХ немесе ВР, ал екінші регистр SI немесе DI бола алады.

ВР регистрі жайлы ескерту. Бұл регистр әдетте элементтерге қатынау үшін стекпен жұмыс істеуде қолданылады, ол жайлы кейінірек қарастырылады. Бұл регистрді жадтың басқа аймақтарынан адресті модификациялауда қолдануға болмайды (дәлірек айтқанда, болады, бірақ ерекше тәсілдермен).

Адресті модификациялау адрестің типін өзгертпейді: егер Х - байттық айнымалының аты болса, онда TYPE X[SI]=BYTE, егер модификатор алдында тұрақтылық өрнегі көрсетілсе (мысалы, 1[BX]) онда ондай адрестің типі анықталмаған болып есептеледі.

Ассемблер тілінде көрсетілген адрестерді жазылуының үш негізгі тәсілдерден басқа, осы үшеуінен туындайтын, түрлері рұқсат етілген.

Бірақ оларды қарастырмас бұрын ассемблер тілінде келісілген команданың операндтарының жазылуында қолданылатын тік жақшалардың қолданылуын сипаттай кетейік:

1) тік жақшаларда регистр-модификаторлардың атауларының жазылуы (ВХ,ВР,SI,DI) осы регистрлердің құрамын алуды көрсетеді (регистрдің аты тік жақшада жазылмаса сол регистрдің өзін көрсетеді).

Мысалы:

A DW 99

AA DW A

. . .

MOV BX,AA ;A адресін BX-ке

MOV CX,[BX] ;CX:=A (CX:=99)

MOV CX,BX ;CX:=BX(CX:=А адресі)

Ескерету. Модификатор емес регистрлердің атауларын тік жақшаларға алып жазуға болмайды.

2) Кез келген өрнекті тік жақшаларға алуға болады, одан оның мағынасы өзгермейді (жақшаны алып тастау, мағынасын өзгертіп жіберу мүмкін).

Мысалы:

MOV CX,[2] ;=MOV CX,2

MOV CX,[A] ;=MOV CX,A

MOV CX,[A+2[BX]] ;=MOV CX,A+2[BX]

3) Келесі жазулар эквиваленті

[x] [y] = [x]+[y] = [x+y]

Басқаша айтқанда, екі өрнекті қатар тік жақшаларға жазу, осы өрнектердің қосындысын білдіреді.

Мысалы:

MOV CX,[BX][SI] ;= MOV CX,[BX]+[SI] = MOV CX,[BX+SI]

Осы келісімдерді қосудың коммутативтік қасиетімен бірге қолдансақ және командаларда адрестердің жазылуының үш негізгі тәсіліне сүйенсек, онда адрестерді жазудың басқа нұсқаларын алуға болады. Мысалы, келесі әр жолда бір адрестің жазылуының эквивалентті формалары келтірілген:

A+1,[A+1],[A]+[1],[A][1],A[1],1[A],[A]+1, …

5[SI],[5][SI],[5]+[SI],[SI+5],[SI]+5, …

A-2[BX],[A-2]+[BX],[A-2+BX],A[BX-2],A[BX]-2, …

A[BX][DI],A[BX+DI],[A+BX+DI],A[BX]+[DI], …

0[BX][SI],[BX][SI],[BX]+[SI],[BX+SI],[SI][BX], …

Сонымен, ассемблер тілінде бір адресті әртүрлі тәсілдермен жазуға болады. Дегенмен, мұнда қолданылатын тәсілдердің адрестерді жазудың негізгі үш формасының біріне эквивалентті болу керектігін есте сақтау керек. Қолдануға болмайтын кейбір жағдайлар:

· екі адрестің қосындысы (А+В);

· біреуі (ВХ+2) регистрі болатын қосылғыштардың қосындысы;

· регистрлердің тыйым салынған жазылу түрлері ([SI+DI]);

· модификатор болмайтын регистрлер (A[CX],2[BL]);

· тік жақшалардың сыртындағы атаулар мен сандар ([SI]5,[BX]A).

Сонымен қатар, адрес сан түрінде берілмейді ([5]), онда ол адрес емес тұрақтылық өрнегі болып саналады. Басқа жағдайларда шектулер жоқ, әркім өзіне ұнаған жазудың түрін таңдайды. Келешекте біз жақшалардың алдында айнымалының аты, ал басқа қосылғыштары тік жақшада жазылатын түрін қолданамыз. Бұл жазулар программалау тілдерінде индексті айнымалыларды белгілеуге ұқсас (A[i+3]).

Тағыда бір ескерту. Модификаторлы адрестік өрнектерді командалардың операндтарын және кейбір директиваларды (EQU,PTR және т.б.) жазуда қолдануға болады, бірақ мәліметтерді анықтау директиваларында еш қашан қолдануға болмайды. Мысалы,

Х DW 1[SI]

асссемблер оның операндтарын программаны трансляциялау сатысында оның мәнін х ұяшығына жазатын болғандықтан бұл директива қате болып табылады.

Мысалдар

Мұнда массивті өңдеуге арналған мысалдар қарастырылады. Бұл мысалдарда индекстік регистрлерді қолдану және есептің шешімдерін түсіндіру келтіріледі. Мәліметтерді енгізу-шығаруды Паскальда жасалған. Паскальдағы программа негізгі программа болады да, одан ассемблер модулі шақырылады немесе кіріктірілген Ассемблер қолданылады.

Мысал

N EQU 10

X DW N DUP(?) ;X[0..N-1]

Х массивінің элементтерін таңбалы бүтін сандар деп қарастырып, массивтің максималды элементін (егер мұндай элементтер бірнешеу болса біріншісін) және оның индексін табу керек.

Шешуі.Адрес (X[i]=X+2*i) болғандықтан индекстік регистр ретінде қолданылатын регистрде (айталық SI регистрінде) екі еселенген индексті (2*і) қолдануға тура келеді. Әзірге максималды элемент және оның индексі ізделгенде екі еселенген индекспен жұмыс жасалады, содан соң ғана соңында максимальды элементтің екі еселенген индексін, нақтылы индексті табу үшін, екіге бөлеміз.

Паскальда жазылған Mas_Max.pas программасының мәтіні:

Program Mas_Max; {$L Mas_Max.obj} { SIM.obj Ассемблер модулін қосу} {$f+}{FAR–процедуралар мен функцияларды шақыру директивасы} label l1,l2; type m: array[0..100] of byte; var n: word; i: byte; Max: word; x: m; {Ассемблерде жазылған сыртқы процедураның сипаттамасы} Procedure Mas_Max(var n:word;X:m; var i:byte; mas:word);{FAR;}external; begin Writeln('Массиитің элементтер саны='); Readln(N); For i:=1 to n Do Read(X[i]); Mas_Max (n,x,I,Max); Writeln('i=',I,’ Max=’,Max); Readln end.

Ассемблерде жазылған Mas_Max.asm модулінің мәтіні:

;Mas_Max.asm Ассемблер модулінің мәтіні .MODEL Large .data ;Мәліметтер Паскальдан алынып-беріледі ;n массивтің элементтер саны, Х берілген массив Extrn n:Word, x:word ;нәтижесі: Max және оның индекісі І Extrn i:byte, max:word .code Public Mas_Max Mas_Max proc far MOV BX,X ;BX=X[0] (бастапқы max) MOV ax,0 ;AX=2*(max-тың индексі),ағашқыда 0 MOV SI,0 ;SI=2*і MOV CX,N ;цикл есептегіші l1: CMP X[SI],BX ;X[i]= max? JLE l2 ;X[i]<= max болғанда àL2 MOV BX,X[SI] ;жаңа max-ды сақтау MOV ax,si ;max-нің индексі l2: ADD SI,2 ;SI=SI+2 LOOP l1 ;àL1 MOV CL,2 ;CL=2 DIV CL ;CL div 2 mov,bx ;max mov i,al ;i ret Mas_Max endp End

Мысал

N EQU 50

S DB N DUP(?) ;S[0 . . N-1]

Y массивінің элементтерін екі орынға алға біртіндеп жылжыту керек.

(S[0],S[1],S[2],…,S[N-1])à(S[2],…,S[N-1],S[0],S[1])

Шешуі.Мұнда циклда S[i]=S[i+2] амалын орындау керек. Осылайша, егер индекстік регистрде (айталық DI –де) олардың біреуінің индексі (і) жазылса, онда Y массивінің көршілес элементіне де сілтеме жасайды. Y[i+2] элементіне сілтеме жасау алдында ол регистрдің мәнін арнайы жолмен әрине өзгертуге (і+2-ні жазуға), содан соң оның алғашқы мәнін (і) қалпына келтіру арқылы жасауға болады. Бірақ та басқаша жасаған жеңілірек:

(S[i])=Y+i

(S[i+2])= S+(i+2)=(S+2)+i

болса, онда DI=i болғанда S[i]-ге cілтеме S[DI] адрестік өрнегімен беріледі, ал S[i+1]-ге сілтеме S+2[DI] немесе S[DI+2] өрнегімен беріледі. Сөйтіп, 2-ні қосуды, индекстік регистрде жасаудан көрі, команданың өзінде көрсеткен ыңғайлы.

Кіріктірілген Ассемблерді пайдаланып Паскальда жазылған Mas_ Misal_2.pas программасының мәтіні:

Program Mas_Misal_2; label l1; type m: array[0..100] of byte; var n: word; i: byte; Y: m; begin Writeln('Массиитің элементтер саны='); Readln(N); For i:=1 to n Do Read(X[i]); asm LEA BX,Y MOV AH,[BX] ;Y[0] және Y[1]-ді құтқару MOV AL, [BX+1] MOV CX,N ;цикл есептегіші ADD CX,2 ; CX=N+2(алға жылжулар саны) L1: MOV DH,[BX+2] MOV [BX],DH ;Y[i]:=Y[i+2] INC BX ;i:=i+1 LOOP L1 MOV [BX],AH ;Y[n-2]:=Y[0] MOV [BX+1],AL ;Y[n-1]:=Y[1] end; For i:=1 to n Do WRITELN(‘Y[‘ , I, ’]=’, Y[i]); end.

Мысал

N EQU 50

Y DB N DUP(?) ;Y[0 . . N-1]

S массивінің симметриялы екендігін, яғни оның массивтің шеттерінен бірдей қашықтықтарда орналасқан элементтері тең екендігін анықтау қажет және 1 (симметриялы) немесе 0 (симметриялы емес) нәтижені AL регистріне жазу қажет.

Шешуі.Мұнда циклда S[i]-ші және S[N-1-і], і 0-ден (N div 2)-ге дейін өзгереді, элементтерін салыстыру керек. Әрине бірінші элементке қатынау үшін і-ші индексті біліп, екінші элементке қатынау үшін N-1-i индексін алуға болады, дегенмен ол үшін бірнеше команда орындау қажет. N-1-i шамасын жаңа (j) индексі деп есептеп, бірден і мен j-ді бір уақытта бірге арттыру арқылы екі индекспен жұмыс істеуге болады.

Паскальда жазылған SIM_PAS.pas программасының мәтіні:

Program SIM_PAS;

{$L SIMMET.obj} { SIM.obj Ассемблер модулін қосу}

{$f+}{FAR–процедуралар мен функцияларды шақыру директивасы}

label l1,l2;

type m:array[0..10] of byte;

var n:word; x,i:byte;

s:m;

{Ассемблерде жазылған сыртқы процедураның сипаттамасы}

Procedure SIM(var n:integer;s:m; var d:integer);{FAR;}external;

begin

Writeln('Массиитің элементтер саны='); Readln(N);

For i:=1 to n Do Read(s[i]);

SIM (n,s,x);

Writeln('X=',X);

Readln

end.

Ассемблерде жазылған SIM.asm модулінің мәтіні:

;mis_Mas.asm

;Sim_Mas Ассемблер модулінің мәтіні

.MODEL Large

.data

;мәліметтер Паскальдан алынып-беріледі

;n массивтің элементтер саны, s

Extrn n:Word, s:byte

;нәтиже: массив симмериялы болса X=1, әйтпесе X=0

Extrn x:byte

.code

Public sim

sim proc far

mov dl,2 ;dl=2

MOV x,0 ;x=0

MOV SI,0 ;i:=0

MOV DI,N

dec di ;j:=n-1

mov ax,n

div dl ;n div 2

MOV Cl,al ;Cl=n div 2

mov ch,0 ;CX=n div 2

;салыстырылатын жұптар саны

L1: MOV AH,S[SI]

CMP AH,S[DI] ;S[i]=S[j]?

JNE FIN ;тең емес ? AL=0-мен шығу

INC SI ;i:=i+1

DEC DI ;j:=j-1

LOOP SYM ;à L1

MOV x,1 ;барлық жұптар тең ? X=1

L2:

ret

sim endp

End

8.1.3.4-мысал. Матрицаның жолының алғашқы элементі сол жолда тағы да кездесетін жолдар санын АL регистріне жазу керек.

Шешуі. Матрицаның элементтерін жол бойымен орналастыруда (алғашқы 20 байт – матрицаның бірінші жолы, келесі 20 байт - екінші жолы және т.с.с.) А[I,j] элементінің адресі А+20*i+j. Мұндағы 20*і шамасын сақтау үшін ВХ регистрін аламыз, ал j-ді сақтау үшін SI регистрін аламыз, онда A[BX] - матрицаның і-ші жолының алғашқы адресі, ал A[BX] [SI] сол жолдың j-ші элементінің адресі.

MOV AL,0 ;ізделетін жолдар саны, алғашқыда 0

;сыртқы цикл (жолдар бойынша)

MOV CX,10 ;сыртқы цикл есептегіші

MOV BX,0 ;А-дан (20*і) жолдың басына дейін өту

L: MOV AH,A[BX] ;АН жолдың алғашқы элементі

MOV DX,CX ;сыртқы циклдың СХ-ін құтқару

;бағандар бойынша ішкі цикл

MOV CX,19 ;ішкі цикл есептегіші

MOV SI,0 ;j-ші жолдағы элементтің индексі

L1: INC SI ;j:=j+1

CMP A[BX][SI],AH ;A[i,j]=AH?

LOOPNE L1 ;әзірше A[i,j]<>AH болғанынша циклды қайлалау

JNE L2 ;AH қайталанған жоқ àL2

INC AL ;жолды есепке алу

;ішкі цикл соңы

L2: MOV CX,DX ;СХ-ті сыртқы цикл үшін қалпына келтіру

ADD BX,20 ;келесі жолдың басына өту

LOOP L ;10 рет циклды қайталау

Дәріс №11,12