Unicode:
; eax = buffer, ebx = string
push ebx eax
.loop:
mov dl,byte [ebx]
test dl,dl
jz .ok
mov byte [eax],dl
inc eax
inc eax
mov byte [eax],0
inc ebx
jmp .loop
.ok:
inc eax
mov word [eax],0
pop eax ebx
ret
FAQ, алгоритмы, макросы....
Предлагаю в этой теме выкладывать всевозможные алгоритмы, макросы, процедуры, включаемые файлы которые будут в некоторой степени полезны при програмировани на ассемблере.
функция dword_to_STR конвертирует число размером в двойное слово в строку
[highlight=asm]
dword_to_STR:
;на входе EAX число 32 бит
; ESI указатель на строку
; EBX разрядность результата
pushad
cmp ebx, 16
ja .end
xor ecx, ecx
jmp .repeat
.mesto db 32 dup (0)
.repeat:
xor edx, edx
div ebx
mov edi, eax
mov al, dl
cmp al, 10
sbb al, 69h
das
mov byte [.mesto+ecx], al
mov eax, edi
inc ecx
cmp eax, 0
jz .endrep
jmp .repeat
.endrep:
mov edi, .mesto
add edi, ecx
.copyrep:
dec edi
mov dl, byte [edi]
mov byte [esi], dl
inc esi
loop .copyrep
.end:
popad
ret
[/highlight]
хочу подметить что она может выводить число в любой системе счисления (разумеетя от 2 до 16), само число может быть размером в слово (AX) или байт (AL), главное что бы старшие части регистра EAX были нулями
пример использования:
[highlight=asm]
simv db 32 dup (0),0
mov eax,0F12CD44h
mov esi, simv
mov ebx, 16
call dword_to_STR
push 0
push simv
push simv
push 0
call [MessageBox]
[/highlight]
http://www.azillionmonkeys.com/qed/asmexample.html с многочисленными примерами оптимизированных алгоритмов.
Еще — сайт Ray Filiatreault с библиотекой по комплексным числам, BCD, с фиксированной запятой и туториалом с библиотекой по программированию сопроцессора: http://www.ray.masmcode.com/
См. сайт
Еще — сайт Ray Filiatreault с библиотекой по комплексным числам, BCD, с фиксированной запятой и туториалом с библиотекой по программированию сопроцессора: http://www.ray.masmcode.com/
[highlight=asm]
GetZSLength:
; get zero-string length
;IN
; EDI ZS offset
;OUT
; EAX ZS length
push ecx
push esi
cld
xor al, al
mov ecx, 0FFFFFFFFh
mov esi, edi
repne scasb
sub edi, esi
mov eax, edi
dec eax
pop esi
pop ecx
ret
[/highlight]
[highlight=asm]
GET_CRC32:
; IN
; ESI = block offset
; EDI = block size
; OUT
; EAX = CRC32
push esi
push edi
push ecx
push ebx
push edx
cld
xor ecx,ecx
dec ecx
mov edx,ecx
.NextByteCRC:
xor eax,eax
xor ebx,ebx
lodsb
xor al,cl
mov cl,ch
mov ch,dl
mov dl,dh
mov dh,8
.NextBitCRC:
shr bx,1
rcr ax,1
jnc .NoCRC
xor ax,08320h
xor bx,0EDB8h
.NoCRC:
dec dh
jnz .NextBitCRC
xor ecx,eax
xor edx,ebx
dec edi
jnz .NextByteCRC
not edx
not ecx
mov eax,edx
rol eax,16
mov ax,cx
pop edx
pop ebx
pop ecx
pop edi
pop esi
ret
[/highlight]
http://win32assembly.online.fr/files/md5asm.zip (сам алгоритм и пример использования)
Таже самая функция только для синстаксиса FASM (перевёл сам лично и добавил ещё две вспомогательные процедурки). пример использования также приложен в архиве
[FONT="Courier New"]S..T..R..O..K..A
[COLOR="Navy"]53 54 52 4F 4B 41[/COLOR] 00[/FONT]
в Юникод-строку, с нуль-темперированным завершением:
[FONT="Courier New"]S.....T.....R.....O.....K.....A..........
[COLOR="Navy"]53[/COLOR] 00 [COLOR="Navy"]54[/COLOR] 00 [COLOR="Navy"]52[/COLOR] 00 [COLOR="Navy"]4F[/COLOR] 00 [COLOR="Navy"]4B[/COLOR] 00 [COLOR="Navy"]41[/COLOR] 00 00 00[/FONT]
Код:
Код:
dword_to_STR:
;на входе EAX число 32 бит
; ESI указатель на строку
; EBX разрядность результата
pushad
cmp ebx, 16
ja .end
cmp eax, 7FFFFFFFh
jna .sign_plus
mov byte [esi], '-'
inc esi
not eax
inc eax
.sign_plus:
xor ecx, ecx
jmp .repeat
.mesto db 32 dup (0)
.repeat:
xor edx, edx
div ebx
mov edi, eax
mov al, dl
cmp al, 10
sbb al, 69h
das
mov byte [.mesto+ecx], al
mov eax, edi
inc ecx
cmp eax, 0
jz .endrep
jmp .repeat
.endrep:
mov edi, .mesto
add edi, ecx
.copyrep:
dec edi
mov dl, byte [edi]
mov byte [esi], dl
inc esi
loop .copyrep
.end:
popad
ret
;на входе EAX число 32 бит
; ESI указатель на строку
; EBX разрядность результата
pushad
cmp ebx, 16
ja .end
cmp eax, 7FFFFFFFh
jna .sign_plus
mov byte [esi], '-'
inc esi
not eax
inc eax
.sign_plus:
xor ecx, ecx
jmp .repeat
.mesto db 32 dup (0)
.repeat:
xor edx, edx
div ebx
mov edi, eax
mov al, dl
cmp al, 10
sbb al, 69h
das
mov byte [.mesto+ecx], al
mov eax, edi
inc ecx
cmp eax, 0
jz .endrep
jmp .repeat
.endrep:
mov edi, .mesto
add edi, ecx
.copyrep:
dec edi
mov dl, byte [edi]
mov byte [esi], dl
inc esi
loop .copyrep
.end:
popad
ret
Код:
STR_to_DWORD:
; IN ESI = указатель на ZS строку
; EAX = разрядность
; OUT EAX = результат
push esi
push ebx
push edi
push edx
push ecx
cmp eax, 16
ja .error
cmp eax, 2
jb .error
mov ecx, eax
mov edi, esi
call GetZSLength
mov edi, eax
add edi, esi ; edi point to end ZS
xor eax, eax
xor edx, edx
inc edx
.rep:
dec edi
xor ebx, ebx
mov bl, [edi]
cmp bl, 30h
jb .error
cmp bl, 39h
jna .digit
cmp bl, 41h
jb .error
@@:
cmp bl, 46h
jna .sim_upcase
cmp bl, 61h
jb .error
@@:
cmp bl, 66h
jna .sim_lowcase
ja .error
.digit:
sub bl, 30h
jmp @f
.sim_upcase:
sub bl, 37h
jmp @f
.sim_lowcase:
sub bl, 57h
@@:
cmp bl, cl
ja .error
imul ebx, edx
add eax, ebx
imul edx, ecx
cmp edi, esi
jnz .rep
.endrep:
jmp @f
.error:
xor eax, eax
@@:
pop ecx
pop edx
pop edi
pop ebx
pop esi
ret
; IN ESI = указатель на ZS строку
; EAX = разрядность
; OUT EAX = результат
push esi
push ebx
push edi
push edx
push ecx
cmp eax, 16
ja .error
cmp eax, 2
jb .error
mov ecx, eax
mov edi, esi
call GetZSLength
mov edi, eax
add edi, esi ; edi point to end ZS
xor eax, eax
xor edx, edx
inc edx
.rep:
dec edi
xor ebx, ebx
mov bl, [edi]
cmp bl, 30h
jb .error
cmp bl, 39h
jna .digit
cmp bl, 41h
jb .error
@@:
cmp bl, 46h
jna .sim_upcase
cmp bl, 61h
jb .error
@@:
cmp bl, 66h
jna .sim_lowcase
ja .error
.digit:
sub bl, 30h
jmp @f
.sim_upcase:
sub bl, 37h
jmp @f
.sim_lowcase:
sub bl, 57h
@@:
cmp bl, cl
ja .error
imul ebx, edx
add eax, ebx
imul edx, ecx
cmp edi, esi
jnz .rep
.endrep:
jmp @f
.error:
xor eax, eax
@@:
pop ecx
pop edx
pop edi
pop ebx
pop esi
ret
следующая функция, тоже конвертирует сроку в число, использует вышеприведённый алгоритм, вот только она принимает только строку, разрядность определяет сама по символу в конце строки (если h то шестнадцатеричное, если o то восьмеричное, если b, то двоичное, иначе десятеричное, если число нпаример в двенадцатеричной системе, а в конце стоит буква b, то ошибку распознает вышеуказанная функция и результат всё равно будет 0), так же функция определяет знак числа
Код:
STR_to_DWORD_EX:
; IN ESI = pointer to ZS
; OUT EAX = result
push esi
push ebx
push edi
xor ebx, ebx
cmp byte [esi], '-'
jnz .sign_plus
mov ebx, 1
inc esi
.sign_plus:
mov edi, esi
call GetZSLength
mov edi, eax
add edi, esi
dec edi
cmp byte [edi], "b"
jnz .oct
mov eax, 2
xchg byte [edi], bh
jmp .convert
.oct:
cmp byte [edi], "o"
jnz .hex
mov eax, 8
xchg byte [edi], bh
jmp .convert
.hex:
cmp byte [edi], "h"
jnz .decim
mov eax, 16
xchg byte [edi], bh
jmp .convert
.decim:
mov eax, 10
mov bh, byte [edi]
.convert:
call STR_to_DWORD
xchg byte [edi], bh
xor bh, bh
cmp ebx, 1
jnz .end
xor ebx, ebx
sub ebx, eax
mov eax, ebx
.end:
pop edi
pop ebx
pop esi
ret
; IN ESI = pointer to ZS
; OUT EAX = result
push esi
push ebx
push edi
xor ebx, ebx
cmp byte [esi], '-'
jnz .sign_plus
mov ebx, 1
inc esi
.sign_plus:
mov edi, esi
call GetZSLength
mov edi, eax
add edi, esi
dec edi
cmp byte [edi], "b"
jnz .oct
mov eax, 2
xchg byte [edi], bh
jmp .convert
.oct:
cmp byte [edi], "o"
jnz .hex
mov eax, 8
xchg byte [edi], bh
jmp .convert
.hex:
cmp byte [edi], "h"
jnz .decim
mov eax, 16
xchg byte [edi], bh
jmp .convert
.decim:
mov eax, 10
mov bh, byte [edi]
.convert:
call STR_to_DWORD
xchg byte [edi], bh
xor bh, bh
cmp ebx, 1
jnz .end
xor ebx, ebx
sub ebx, eax
mov eax, ebx
.end:
pop edi
pop ebx
pop esi
ret
(в конце должен быть 1 нулевой байт)
Код:
GetZSLength_UTF8:
;get UTF-8 zero-string length
;IN
; EDI UTF-8 ZS offset
;OUT
; EAX UTF-8 ZS length
pushad
xor eax,eax
.repeat:
mov bl, [edi]
cmp bl, 0
jz .endrepeat
shr bl, 4
cmp bl, 01000b
jnb .not_onebyte
inc edi
jmp .next_char
.not_onebyte:
cmp bl, 01101b
ja .not_twobyte
add edi, 2
jmp .next_char
.not_twobyte:
cmp bl, 01110b
ja .four_byte
add edi, 3
jmp .next_char
.four_byte:
add edi, 4
.next_char:
inc eax
jmp .repeat
.endrepeat:
mov [esp+28], eax
popad
ret
;get UTF-8 zero-string length
;IN
; EDI UTF-8 ZS offset
;OUT
; EAX UTF-8 ZS length
pushad
xor eax,eax
.repeat:
mov bl, [edi]
cmp bl, 0
jz .endrepeat
shr bl, 4
cmp bl, 01000b
jnb .not_onebyte
inc edi
jmp .next_char
.not_onebyte:
cmp bl, 01101b
ja .not_twobyte
add edi, 2
jmp .next_char
.not_twobyte:
cmp bl, 01110b
ja .four_byte
add edi, 3
jmp .next_char
.four_byte:
add edi, 4
.next_char:
inc eax
jmp .repeat
.endrepeat:
mov [esp+28], eax
popad
ret
Нахождение количетсва символов в UFT-16 строке (Little Endian)
(в конце должно быть два нулевых байта)
Код:
GetZSLength_UTF16:
;get UTF-16 zero-string length (UTF-16LE)
;IN
; EDI UTF-16 ZS offset
;OUT
; EAX UTF-8 ZS length
pushad
xor eax,eax
.repeat:
mov bx, [edi]
cmp bx, 0
jz .endrepeat
shr bx, 10d
cmp bx, 0110110b
jz .not_twobyte
add edi, 2
jmp .next_char
.not_twobyte:
add edi, 4
.next_char:
inc eax
jmp .repeat
.endrepeat:
mov [esp+28], eax
popad
ret
;get UTF-16 zero-string length (UTF-16LE)
;IN
; EDI UTF-16 ZS offset
;OUT
; EAX UTF-8 ZS length
pushad
xor eax,eax
.repeat:
mov bx, [edi]
cmp bx, 0
jz .endrepeat
shr bx, 10d
cmp bx, 0110110b
jz .not_twobyte
add edi, 2
jmp .next_char
.not_twobyte:
add edi, 4
.next_char:
inc eax
jmp .repeat
.endrepeat:
mov [esp+28], eax
popad
ret
;------------------- 1.ПЕРЕХОД НА НОВУЮ СТРОКУ ---------------------
; используется прерывание BIOS 10H
; использует текущую страницу дисплэя
; в процедуре используются регистры : AX
[highlight=asm]
NEW_LINE PROC NEAR
MOV AH, 0EH ; писать символ на активную видео страницу (эмуляция телетайпа), инициатор - прерывание 10Н
MOV AL, 0AH ; перевод строки
INT 10H
MOV AH, 0EH ; писать символ на активную видео страницу (эмуляция телетайпа), инициатор - прерывание 10Н
MOV AL, 0DH ; возврат каретки
INT 10H
RET
NEW_LINE ENDP
[/highlight]
; ---2.ОЧИСТКА ДИСПЛЭЯ, ПЕРЕВОД КУРСОРА НА КООРДИНАТЫ [0,0] С
;-------------СОХРАНЕНИЕМ ТЕКУЩЕГО ВИДЕОРЕЖИМА ------------------
; используется прерывание BIOS 10H
; в процедуре используются регистры : AX
[highlight=asm]
CLRSCR PROC NEAR
MOV AH, 0FH ; читать текущий видео режим (сохраняется в регистр AL), инициатор - прерывание 10Н
INT 10H ; вызов прерывания 10Н
MOV AH, 00H ; уст. видео режим, очистить экран(режим остается прежний, т.к AL не изменяется), инициатор - прерывание 10Н
INT 10H ; вызов прерывания 10Н
RET
CLRSCR ENDP
[/highlight]
; -- 3.ВЫВОД СТРОКИ НА ДИСПЛЭЙ (ПРЯМАЯ РАБОТА С ВИДЕОПАМЯТЬЮ) -; работает с прямым доступом к видеопамяти
; в конце строки должен обязательно присутствовать символ конца строки - 00H
; в сегменте данных объявить буффер для хранения строк с атрибутами перед пересылкой в видеопамять : BUFFER_DIRECT_DISPLAY_LINE DW 50 DUP (?)
; перед вызовом процедуры занести в SI адресс первого элемента строки : LEA SI, LINE
; перед вызовом процедуры занести в AH атрибуты выводимого символа : MOV AH, 07H
; в процедуре используются регистры : AX, DI, SI, CX
Код:
DISPLAY_LINE_DIR_MEM PROC NEAR
; подготовка строки и пересылка ее в буффер
MOV BX, DS
MOV ES, BX ; установка ES на начало сегмента данных
CLD ; сброс флага D - обработка строк в прямом направлении
LEA DI, BUFFER_DIRECT_DISPLAY_LINE ; установка регистра DI на начало буффера
TRANS_LINE:
MOV AL, BYTE PTR [SI] ; загрузка очередного символа
OR AL, AL ; проверка на конец строки (00H)
JZ SHORT RETRY ; выход из цикла подготовки строки
STOSW ; запись слова с АХ в строку по адресу ES:DI (INC DI выполняется автоматически)
INC SI ; переход на очередной символ
JMP SHORT TRANS_LINE
RETRY:
; пересылка строки в видеопамять
SHR DI, 1 ; деление DI на 2 (кол-во байт, записанных в буффер), получаем кол-во слов в буффере
MOV CX, DI
MOV AX, 0B800H ; занесение в AX адреса начала сегмента видеопамяти
MOV ES, AX ; установка сегмента ES на начало сегмента видеопамяти
LEA SI, BUFFER_DIRECT_DISPLAY_LINE ; установка SI на начало буффера
XOR DI, DI
REP MOVSW ; копируется СХ слов из DS:SI (сегмент данных программы) в ES:DI (сегмент видеопамяти)
RET
DISPLAY_LINE_DIR_MEM ENDP
; подготовка строки и пересылка ее в буффер
MOV BX, DS
MOV ES, BX ; установка ES на начало сегмента данных
CLD ; сброс флага D - обработка строк в прямом направлении
LEA DI, BUFFER_DIRECT_DISPLAY_LINE ; установка регистра DI на начало буффера
TRANS_LINE:
MOV AL, BYTE PTR [SI] ; загрузка очередного символа
OR AL, AL ; проверка на конец строки (00H)
JZ SHORT RETRY ; выход из цикла подготовки строки
STOSW ; запись слова с АХ в строку по адресу ES:DI (INC DI выполняется автоматически)
INC SI ; переход на очередной символ
JMP SHORT TRANS_LINE
RETRY:
; пересылка строки в видеопамять
SHR DI, 1 ; деление DI на 2 (кол-во байт, записанных в буффер), получаем кол-во слов в буффере
MOV CX, DI
MOV AX, 0B800H ; занесение в AX адреса начала сегмента видеопамяти
MOV ES, AX ; установка сегмента ES на начало сегмента видеопамяти
LEA SI, BUFFER_DIRECT_DISPLAY_LINE ; установка SI на начало буффера
XOR DI, DI
REP MOVSW ; копируется СХ слов из DS:SI (сегмент данных программы) в ES:DI (сегмент видеопамяти)
RET
DISPLAY_LINE_DIR_MEM ENDP
; ---------- 4.ВЫВОД СТРОКИ НА ДИСПЛЭЙ (ПРЕРЫВАНИЕ BIOS) ----------
; используется прерывание BIOS 10H
; в конце строки должен обязательно присутствовать символ конца строки - 00H
; перед вызовом процедуры занести в SI адресс первого элемента строки : LEA SI, LINE
; перед вызовом процедуры занести в BH номер видеостраницы на которую выведется строка : MOV BH, 00Н
; перед вызовом процедуры занести в BL цвет текста сроки : MOV BL, 07H
; в процедуре используются регистры : SI, AX, BX, CX, DX
Код:
DISPLAY_LINE_BIOS_INT PROC NEAR
MOV AH, 03H ; считывание текущего положения курсора (DH - строка, DL - столбец)
INT 10H ; вызов прерывания BIOS 10H
MOV CX, 01H ; счетчик (сколько экземпляров одного символа писать)
DISP:
MOV AL, [SI] ; пересылка в АХ очередного символа
OR AL, AL ; проверка на конец строки (00H)
JZ SHORT RETRY ; если встретился символ "конец строки" переходим по метке RETRY
MOV AH, 09H ; писать символ/атрибут в текущей позиции курсора
INT 10H ; вызов прерывания BIOS 10H
INC SI ; переход к следующему символу строки
INC DL ; переходим на следующую по горизонтали позицию курсора (переход по вертикали обеспечивает DOS)
MOV AH, 02H ; установить положение курсора
INT 10H ; вызов прерывания BIOS 10H
JMP SHORT DISP ; переход по метке DISP для вывода следующего символа
RETRY:
RET
DISPLAY_LINE_BIOS_INT ENDP
MOV AH, 03H ; считывание текущего положения курсора (DH - строка, DL - столбец)
INT 10H ; вызов прерывания BIOS 10H
MOV CX, 01H ; счетчик (сколько экземпляров одного символа писать)
DISP:
MOV AL, [SI] ; пересылка в АХ очередного символа
OR AL, AL ; проверка на конец строки (00H)
JZ SHORT RETRY ; если встретился символ "конец строки" переходим по метке RETRY
MOV AH, 09H ; писать символ/атрибут в текущей позиции курсора
INT 10H ; вызов прерывания BIOS 10H
INC SI ; переход к следующему символу строки
INC DL ; переходим на следующую по горизонтали позицию курсора (переход по вертикали обеспечивает DOS)
MOV AH, 02H ; установить положение курсора
INT 10H ; вызов прерывания BIOS 10H
JMP SHORT DISP ; переход по метке DISP для вывода следующего символа
RETRY:
RET
DISPLAY_LINE_BIOS_INT ENDP
; ----------- ПЕРЕХОД НА СЛЕДУЮЩУЮ ПОЗИЦИЮ КУРСОРА ---------------
; используется прерывание BIOS 10H
; вход - ничего
; выход - ничего
; используются регистры - AX, DX
[highlight=asm]
NEXT_CURSOR_POSITION PROC NEAR
MOV AH, 03H ; считывание текущего положения курсора (DH - строка, DL - столбец)
INT 10H ; вызов прерывания BIOS 10H
INC DL ; переходим на следующую по горизонтали позицию курсора (переход по вертикали обеспечивает DOS)
MOV AH, 02H ; установить положение курсора
INT 10H ; вызов прерывания BIOS 10H
RET
NEXT_CURSOR_POSITION ENDP
[/highlight]
; -------------- ПЕРЕХОД НА ПРЕДЫДУЩУЮ ПОЗИЦИЮ КУРСОРА ----------
; используется прерывание BIOS 10H
; вход - ничего
; выход - ничего
; используются регистры - AX, DX
[highlight=asm]
PREVIOS_CURSOR_POSITION PROC NEAR
MOV AH, 03H ; считывание текущего положения курсора (DH - строка, DL - столбец)
INT 10H ; вызов прерывания BIOS 10H
DEC DL ; переходим на следующую по горизонтали позицию курсора (переход по вертикали обеспечивает DOS)
MOV AH, 02H ; установить положение курсора
INT 10H ; вызов прерывания BIOS 10H
RET
PREVIOS_CURSOR_POSITION ENDP
[/highlight]
------------------------ ПРИЕМ БАЙТА С КЛАВИАТУРЫ -------------------
; вход - ничего; для вывода используется страница дисплэя №0 и белый цвет текста
; выход - введенный с клавиатуры и преобразованный с ASCII байт в стэке
; имеет защиту от ввода букв и управляющих символов, реализованы ф-ции BACKSPASE и ESC (для окончания ввода)
[highlight=asm]
READ_BYTE_TO_KEYBOARD PROC NEAR
XOR AX, AX
PUSH AX ; начальное значение вводимого числа
INPUT_NUMBER:
; прием символа с клавиатуры
MOV AH, 00H
INT 16H ; ASCII-код символа сохраняется в AL
; проверка на символ ESC
CMP AL, 01BH
JZ SHORT END_INPUT ; если он был введен, переходим к метке окончания ввода числа
; проверка на символ BACKSPASE
CMP AL, 08H
JZ SHORT BACKSPASE ; если он был введен, переходим к метке BACKSPASE
; проверка на диапазон 30Н-39H (для защиты от ввода буквы или управляющего символа)
CMP AL, 030H
JB SHORT INPUT_NUMBER
CMP AL, 039H
JA SHORT INPUT_NUMBER
; проверка на границу размера байтового числа
POP BX ; извлечение из стэка ранее введенного значения
PUSH BX ; возврат ранее введенного значения в стэк
CMP BX, 25 ; сравнение уже введенного значения с 25
JA SHORT END_INPUT ; если уже введенное число>25
JNZ SHORT NORMAL ; если уже введенное число !=25
; проверка не третий вводимый символ при первых двух = 25 (защита от ввода числа >255)
CMP AL, 035H
JA SHORT INPUT_NUMBER
NORMAL:
; подготовка к выводу только что введенного символа
MOV BH, 00H ; номер видео страницы
MOV BL, 07H ; выбор цвета текста
; выводим на дисплэй символ (находится в AL)
MOV CX, 01H ; счетчик (сколько экземпляров одного символа писать)
MOV AH, 09H ; писать символ/атрибут в текущей позиции курсора
INT 10H ; вызов прерывания BIOS 10H
; переходим на следующую позицию курсора
MOV AH, 03H ; считывание текущего положения курсора (DH - строка, DL - столбец)
INT 10H ; вызов прерывания BIOS 10H
INC DL ; переходим на следующую по горизонтали позицию курсора (переход по вертикали обеспечивает DOS)
MOV AH, 02H ; установить положение курсора
INT 10H ; вызов прерывания BIOS 10H
; преобразование из ASCII формата
XOR AH, AH ; обнуление АН
SUB AX, 030H ; отнимаем 30Н от АХ
MOV DX, AX
POP AX ; извлечение из стэка предидущего значения
MOV BL, 10 ; умножение его на 10
MUL BL
ADD AX, DX ; и суммирование с только что введенным символом
PUSH AX ; заносим число в стэк
JMP SHORT INPUT_NUMBER
BACKSPASE:
; делим ранее положенное в стэк значение на 10
POP AX
MOV BX, 10
DIV BL
XOR AH, AH ; обнуляем остаток
PUSH AX ; заносим новое значение обратно в стэк
; переход на предидущую позицию курсора
MOV AH, 03H ; считывание текущего положения курсора (DH - строка, DL - столбец)
INT 10H ; вызов прерывания BIOS 10H
DEC DL ; переходим на следующую по горизонтали позицию курсора (переход по вертикали обеспечивает DOS)
MOV AH, 02H ; установить положение курсора
INT 10H ; вызов прерывания BIOS 10H
; стирание предидущего символа
MOV AL, 00H
MOV BH, 00H ; номер видео страницы
MOV BL, 07H ; выбор цвета текста
; выводим на дисплэй символ
MOV CX, 01H ; счетчик (сколько экземпляров одного символа писать)
MOV AH, 09H ; писать символ/атрибут в текущей позиции курсора
INT 10H ; вызов прерывания BIOS 10H
JMP SHORT INPUT_NUMBER
END_INPUT:
POP AX ; меняем местами в стэке адрес возврата и результат
POP BX
PUSH AX
PUSH BX
RET
READ_BYTE_TO_KEYBOARD ENDP
[/highlight]
адрес таблицы страниц расчитывается так:
pta =pdi*4096+ptba
где: pta - адрес таблицы страниц, pdi – индекс в каталоге страниц, ptba – базовый адрес области памяти, где находятся все таблицы страниц.
Код:
PAGE_DIR_BASE_ADDRESS equ 01A00000h ; адрес каталога страниц
PAGE_TABLES_BASE_ADDRESS equ 01200000h ; базовый адрес всех таблиц страниц
create_PDEPTE:
; IN
; EAX page address
; EBX phys page address
pushad
mov edi, ebx
mov edx, eax
shr eax, 22
shl eax, 2
mov esi, PAGE_DIR_BASE_ADDRESS
add esi, eax
shr eax, 2
mov ebx, eax
shl ebx, 12
mov eax, PAGE_TABLES_BASE_ADDRESS
add eax, ebx
or eax, 011b
mov [esi], eax
and eax, 0FFFFF000h
.create_PTE: ;eax = table base address
mov esi, eax
mov eax, edx
shl eax, 10
shr eax, 22
shl eax, 2
add esi, eax
mov eax, edi
or eax, 011b
mov [esi], eax
.end:
popad
ret
PAGE_TABLES_BASE_ADDRESS equ 01200000h ; базовый адрес всех таблиц страниц
create_PDEPTE:
; IN
; EAX page address
; EBX phys page address
pushad
mov edi, ebx
mov edx, eax
shr eax, 22
shl eax, 2
mov esi, PAGE_DIR_BASE_ADDRESS
add esi, eax
shr eax, 2
mov ebx, eax
shl ebx, 12
mov eax, PAGE_TABLES_BASE_ADDRESS
add eax, ebx
or eax, 011b
mov [esi], eax
and eax, 0FFFFF000h
.create_PTE: ;eax = table base address
mov esi, eax
mov eax, edx
shl eax, 10
shr eax, 22
shl eax, 2
add esi, eax
mov eax, edi
or eax, 011b
mov [esi], eax
.end:
popad
ret
Функция принимает в ESI указатель на строку, и в EDI указатель на переменную, в которую будет сохранено значение. Если нужна меньшая точность, то надо будет изменить только одну строку (я её пометил). Разделитель целой и дробной части задаётся в decimal_separator. Если в строке имеются символы отличные от чисел и разделителя (ошибка), то результат не сохраняется. ВАЖНО: проверка на присутствие двух разделителей не осуществляется!!! (если в строке два разделителя, то результат будет неадекватным)
Код:
STR_to_FLOAT:
; converting string to float value
;IN
; ESI - ZS offset
; EDI - pointer to value
decimal_separator equ '.'
pushad
xchg edi, esi
call GetZSLength
xchg edi, esi
mov ecx, eax
mov edx, eax
mov ebx, 10
fldz
xor eax, eax
push eax ; [esp] - temp value
.repeat:
cmp byte [esi], '9'
ja .error
cmp byte [esi], '0'
jnb @f
cmp byte [esi], decimal_separator
jnz .error
jmp .continue
@@:
mov [esp], ebx
fimul dword [esp]
mov al, byte [esi]
sub al, '0'
mov [esp], eax
fiadd dword [esp]
.continue:
dec ecx
inc esi
cmp ecx, 0
jnz .repeat
.endrepeat:
xchg esi, edi
mov al, decimal_separator
mov ecx, edx
sub edi, edx
repnz scasb ;
cmp ecx, 0
jz .end
mov dword [esp], 10
.rep:
fidiv dword [esp]
loop .rep
.end:
fstp tbyte [esi] ; <------ saving float value
.error:
pop eax ; delete temp value
popad
ret
; converting string to float value
;IN
; ESI - ZS offset
; EDI - pointer to value
decimal_separator equ '.'
pushad
xchg edi, esi
call GetZSLength
xchg edi, esi
mov ecx, eax
mov edx, eax
mov ebx, 10
fldz
xor eax, eax
push eax ; [esp] - temp value
.repeat:
cmp byte [esi], '9'
ja .error
cmp byte [esi], '0'
jnb @f
cmp byte [esi], decimal_separator
jnz .error
jmp .continue
@@:
mov [esp], ebx
fimul dword [esp]
mov al, byte [esi]
sub al, '0'
mov [esp], eax
fiadd dword [esp]
.continue:
dec ecx
inc esi
cmp ecx, 0
jnz .repeat
.endrepeat:
xchg esi, edi
mov al, decimal_separator
mov ecx, edx
sub edi, edx
repnz scasb ;
cmp ecx, 0
jz .end
mov dword [esp], 10
.rep:
fidiv dword [esp]
loop .rep
.end:
fstp tbyte [esi] ; <------ saving float value
.error:
pop eax ; delete temp value
popad
ret
Думаю такие процедуры здесь приводить не стоит. Вместе с MASM32 идёт набор процедур для работы с вещественными числами, все с подробными комментариями.
Цитата: ahilles
а какие "более востребованы"?
Самые распространённые - преобразование числа в строку и обратно. Но их не проблема найти. Как показывают темы в этом разделе, у людей просто проблема с использованием поисковиков :-\
Цитата: ahilles
Для начала выложу функцию по преобразованию числа в строку.
функция dword_to_STR конвертирует число размером в двойное слово в строку
[/highlight]
функция dword_to_STR конвертирует число размером в двойное слово в строку
[/highlight]
Для начинающих я думаю не плохо было бы с комментариями. если конечно можно.. спасибо