{ case N1: act_1; break;

case N2: act_2; break;

case Nk: act_k; break;

default: act_d;

}

1.  Вариант if-elseif-…-else

if (var==N1) act_1;

else if (var ==N2) act_2;

else if (var ==Nk) act_k;

else act_d;

Дома пример для двух ассемблеров и оценку числа команд (мин, мах, среднее)

2.  Ветвление по таблице меток с индексом var

if (var < N1 && var > Nk) goto ldefault;

reg = 2 * (var – N1); // для FAR i8086 4 * (..)

// Ассемблер-код

// для i8086: JMP TBL[REG]

// для PDP-11: JMP @TBL(REG)

L1:

L2:

LDEFAULT:

Дома две реализации на ассемблерах

3.  Случай большого диапазона N1..Nk с числом вариантов много меньшим величины Nk-N1

Две таблицы: таблица значений и таблица меток.

Дома – алгоритм на Си-подобном языке и две ассемблер-программы для I8086:

а) near-метки;

б) far-метки

Версия PDP-11:

TBLVAR: .WORD N1, N2, …, NK ; Табл. знач.

TBLLAB: .WORD L1, L2, …, LK ; табл. меток

SWITCH: MOV #TBLVAR, R0 ; ГДЕ ИСКАТЬ

MOV N, R1 ; ЧТО ИСКАТЬ

MOV #(TBLLAB-TBLVAR)/2, R2 ;

JSR PC, SEARCH

; В R0 НАХОДИТСЯ АДРЕС

; НАЙДЕННОГО ЭЛЕМЕНТА ИЛИ 0

TST R0

BNE LJMP

LDEFAULT: …

LJMP: SUB #TBLVAR, R0

JMP @TBLLAB(R0)

Дома: 2 варианта search: линейный и бинарный

Цикл с предусловием: while (cond) act;

l_while:

if (cond) goto l_act;

goto l_after; // не short

lact: act;

goto l_while;

l_after:

l_while:

if (!cond) goto l_after;

act;

goto l_while;

l_after:

Дома на двух ассемблерах

Цикл с постусловием: do act; while (cond);

НЕ нашли? Не то? Что вы ищете?

l_do:

act;

if (cond) goto l_do;

l_do:

act;

if (!cond) goto l_after;

goto l_do;

l_after:

Дома на двух ассемблерах

Цикл с параметром

1.  Паскалевский for i=start to fin do

PDP-11:

;m: array[start..fin] of integer;

;for i=start to fin do sum = sum + m[i];

;start <= fin

M: .BLKW FIN – START + 1

MOV #START, R0

L$FOR: MOV R0, R1

ASL R1

ADD M-(START*2)(R1), SUM

INC R0

CMP R0, #FIN

BLE L$FOR

Для I8086 дома

2.  Паскалевский for i=fin downto start do

PDP-11: ; for i=fin downto start do sum = sum + m[i];

; fin > start

MOV #FIN-START+1, R0

L$FOR: MOV R0, R1

ASL R1

ADD M-2(R1), SUM

SOB R0, L$FOR

Для I8086 дома
3. Цикл
for языка Си

Самостоятельно для обоих ассемблеров

Обработка массивов

Последовательный доступ: *pm++;

Статический массив:

; *pm++ = 0

A) Нерегистровый указатель: short *pm;

; PDP-11

CLR @PM

ADD #2, PM

; i8086

MOV SI, PM

MOV WORD PTR [SI], 0

ADD PM, 2

B) Регистровый указатель:

register short *pm;

; PDP-11: pm Û R2

CLR (R2)+

; i8086: pm Û SI

MOV WORD PTR [SI], 0

ADD SI, 2

Проблема распознавания сегмента в процедуре I8086

abc(int *pm)

{ *pm = 0; // указатель pm может указывать как на

// статические данные, так и на локальные

// данные стека

}

Поскольку сама функция abc не может знать сегмента, где адресуемые данные, то 2 варианта:

1) умолчание; 2) far-адрес

Вариант с NEAR-указателем pm

DS всегда должно быть равным SS!!!

Часть процедуры:

PUSH BP

MOV BP, SP

MOV SI, [BP+4] ; pm => SI

MOV WORD PTR [SI], 0

Фаза вызова:

LEA AX, M

PUSH AX

CALL ABC

Вариант с FAR-указателем pm

DS может быть не равным SS!!!

Часть процедуры:

PUSH BP

MOV BP, SP

PUSH ES

LES SI, [BP+4] ; <ES, SI> = pm

MOV WORD PTR ES:[SI], 0

Фаза вызова для статического массива:

PUSH DS ; для локального будет SS!!!

LEA AX, M

PUSH AX

CALL ABC

Модели памяти:

Модель

Распределение объектов программы по сегментам

Тип указателя на данные

Тип указателя на функцию

tiny

все в одном

near

near

small

Код в одном. Данные и стек в другом.

near

near

medium

Код в нескольких.

Данные и стек в одном.

near

far

compact

Код в одном.

Данные и стек в нескольких.

far

near

large

Код в нескольких.

Данные и стек в нескольких.

far

far

huge

“-“

huge

far

flat

как tiny, но все адреса 32-разрядные

32-разр.

32-разр.

Адресная арифметика для различных типов указателей I8086:

; pm += k

near:

pm = pm + k*размер_данных

far:

pmoff= pmoff + k*размер_данных

В общем случае (для любого k):

MOV AX, SIZE_ELEM

MUL AX, K

ADD PM, AX

Для far задействовано только одно слово двухсловного PM.

Указатель типа huge позволяет адресовать
в 16-разрядном режиме массивы размером
более чем 64
kб.
Внутрисегментная часть адреса всегда меньше 16.

Алгоритм увеличения pm на k:

1.  s = pmoff + k*размер_данных

2.  pmoff = s mod 16

3.  pmseg + = pmseg + s div 16

Пример:

Пусть:

pm = 1700:0006 (физ. адрес = )

размер_данных =800h(2 Kб)

k = 40h

1. s = 6+ 40h * 800h = 20006h

2. pmoff = 20006h mod 16 = 6

4.  pmseg + = 1700h + 20006h div 16 = 1700h + 2000h = 3700h

Прямой доступ к элементу массива M[I]

1. Си и статический массив M:

а) вычисление смещения REG = I*SIZE_ELEM;

б) использование [REG+M] для (I8086)

или M(REG) для PDP-11

; short m[20], i;

; m[i] = 3

MOV I, R0

ASL R0

MOV #3, M(R0)

; m[3] = 1

MOV #1, M+6

Дома для i8086

2. Паскаль и статический массив:

а) вычисление смещения REG = I*SIZE_ELEM;

б) использование

[REG+M-START*SIZE_ELEM] для I8086

или M-START*SIZE_ELEM(REG) для PDP-11

Дома для обоих ассемблеров случай int_16 и int_32

3. Случай динамического массива в стеке:

SP =>

Начало области локальных переменных

R5 – M

M[0]

M[1]

M[MAXIND]

другие локальные переменные

R5

старое значение R5

Адрес возврата из подпрограммы

; m[3] = 5

Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5 6