{ 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 |


