D = dn-1dn-2d1d0 - исходное n-разрядное число

D = d0 + d1*q + d2*q2 + d3*q3 + … + dn-1*qn-1

Схема Горнера:

D = (…(dn-1 *q + dn-2)*q + dn-3)*q + …d1)*q + d0

Алгоритм преобразования массива цифр:

for(s = 0, i = n-1; i >= 0; i--)

s = s*q + d[i];

Алгоритм преобразования ASCII-строки цифр, размещенных в массиве char m[];

for(s = 0, register char p = m, i = n; i!= 0; i--)

s = s*q + digit(*p++);

Значения s, получаемые в ходе трассировки при преобразовании числа 1234510 : 0, 1, 12, 123, 1234, 12345

При q <= 10 digit(chr) = chr - '0';

Для q > 10 проводится дополнительный анализ ASCII-цифр, учитывающий кодирование цифр, больших девяти, либо используется таблица преобразования (d=tbl[chr-‘0’]).

; Таблица для шестнадцатиричных

tbl db 0,1,2,3,4,5,6,7,8,9 ; от кодов 30h..39h (’0123456789’)

db 7 dup (?) ; от кодов 3Ah..40 (’:;<=>?@’)

db 10,11,12,13,14,15 ; от кодов 41h..41h (‘ABCDEF’)

Дома: написать фрагмент преобразования ASCI-строки в 16-ричное число, учитывающий возможность строчных и прописных букв A..F, a..f.

Для q = 2k вместо умножения используется сдвиг:

s <<= k, s |= digit(*p++);

Для q = 2 процесс может быть упрощен еще больше

 


PDP-11: S - R1, P - R2, ch - R0, i – R3

x86: S - DX, P - SI, ch - AL, i - CX

CLR

R1

XRA

DX, DX

MOV

#M, R2

LEA

SI, M

MOV

#5, R3

MOV

CX, 5

L:

MOVB

(R2)+, R0

L:

MOV

AL, [SI]

INC

SI

ROR

R0

ROR

AL, 1

ROL

R1

ROL

DX

SOB

R3, L

LOOP

L

Преобразование числа в строку

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

d0 = D mod q

d1 = (D div q) mod q

d2 = ((D div q) div q) mod q

Алгоритм вывода ASCII-строки цифр

for(i = n; i!= 0; i--)

putc(asc(d%q)), d = d / q;

Для q <= 10 asc(x) = x + '0'.

Обработка данных с повышенной точностью

Сложение

sm-1,…,s1,s0

+

am-1,…,a1,a0

-----------

sm-1,…,s1,s0

#define BITLEN 64

#define WLEN BITLEN/16

unsigned int

ma[WLEN] = // массив a0,a1,a2,a3

{0xffff, 0x0001, 0x8000, 0xAAAA},

ms[WLEN] = // массив s0,s1,s2,s3

{0x0001, 0x0002, 0x8000, 0x0001},

*pa, *ps, // сканеры массивов

i, cf; // счетчик и перенос

unsigned long l; // сумма двух int

main()

{ for(pa=ma, ps=ms, i=WLEN, cf=0;

i>0; i--)

{ l = (unsigned long)*pa++

+ *ps + cf;

*ps++ = (unsigned int)l;

cf = *((int *)(&l)+1);

}

}

Дома: написать на 2-х ассемблерах Организация подпрограмм

subr(p_1,…,p_n);

y = func(q_1,…,q_m) + x;

Реализация:

1)  Пересылка p_1,…,p_n в программно-доступные компоненты, выделяемые для представления формальных параметров процедуры subr.

2)  Вызов subr так, чтобы можно было возвратиться к продолжению программы.

3)  Пересылка q_1,…,q_m в программно-доступные компоненты, выделяемые для представления формальных параметров.

4)  Вызов func так, чтобы можно было возвратиться в точку подсуммирования к значению func переменной x.

Основные элементы данных:

АВ - адрес возврата;

МХАВ - место хранения АВ;

ТВ - точка входа в ПП.
Способы сохранения адреса возврата:

1.  В ячейке памяти, принадлежащей подпрограмме.

Пример(PDP-8: МХАВ==mem(ТВ)) :

вызов subr: а) mem(ТВ) = PC; б) PC = ТВ+1

возврат: PC = mem(ТВ) // jump с косвенной адресацией через метку ПП

2. Через стек

Пример(I8086) :

вызов subr:

а) вычисление ТВ и продвижение IP к следующей команде (АВ в IP);

б) сохранение АВ и переход:

// при внутрисегментном переходе

mem(--SP) = IP; IP = ТВ

// при межсегментном переходе

mem(--SP) = CS; mem(--SP) = IP

CS:IP = ТВ

возврат:

// внутрисегментный

IP = mem(SP++);

// межсегментный

IP = mem(SP++); CS = mem(SP++)

После восстановления АВ в IP или CS:IP возможна модификация SP для удаления параметров, передаваемых через стек
3. Через регистр.

Пример(PDP-11):

вызов subr:

а) вычисление ТВ и продвижение PC к следующей команде;

б) сохранение регистра адреса возврата:

mem(--SP) = Ri

в) сохранение адреса возврата и переход:

Ri = PC ; PC = ТВ.

Частный наиболее используемый в PDP-11 случай - Ri = PC. При этом способ 3 вырождается в способ 2(через стек).

Передача параметров в процедуры

Через регистр

;===================================

; CPYRG - копирует R0 байтов памяти (R0 > 0)
; от адреса
R1 в область памяти с адресом R2

; ===================================

CPYRG: MOVB (R1)+,(R2)+ ;

SOB R0, CPYRG ; ЦИКЛ

RETURN ; RTS PC

; Пример вызова CPYRG

SIZE1 = 30

M1: .BLKB SIZE1

M2: .BLKB SIZE1

. . . .

; CPYRG(M1,M2,SIZE1)

MOV #M1, R1

MOV #M2, R2

MOV #SIZE1, R0

CALL CPYRG ; JSR PC, CPYRG

;===================================

; CPYRG - копирует CX байтов памяти (CX > 0)
; от адреса
SI в область памяти с адресом DI

; ===================================

CPYRG PROC NEAR

PUSH DS ; данные в одном

POP ES ; сегменте

CLD ; задать DF, чтобы ++

; повторить CX раз копирование

; do {*ES:DI++ = *DS:SI++;} while(--CX!= 0)

REP MOVSB ; скопировать

RET

CPYRG ENDP

Передача параметров через область памяти, принадлежащую процедуре

Фаза вызова: Подпрограмма:

·

Область формальных

параметров

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

· Вызов подпрограммы

Подпрограмма

 


Проблема видимости при размещении ПП и фазы вызова в разных модулях

В PDP-11:

:: - разделитель в объявлении глобальной метки;

.GLOBL список имен - объявление имен глобальными

В x86:

PUBLIC список имен - объявление имен для помещение в таблицу obj-файла

EXTRN список имен – объявление для разрешение ссылок на неописанные имена

;===================================

; CPYAR - копирует CNT байтов памяти
; от адреса
P1 в область памяти с адресом P2

; ===================================

CNT:: .WORD

P1:: .WORD

P2:: .WORD

CPYAR:: MOVB @P1, @P2

INC P1

INC P2

DEC CNT

BNE CPYAR

RETURN

;Вызов для копирования M1 в M2

.GLOBL CNT, P1,P2,CPYAR

MOV #M1, P1

MOV #M2, P2

MOV #SIZE1, CNT

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