From 9b11245e08ce34e138ddd15203ce3bc414664d7f Mon Sep 17 00:00:00 2001 From: Akyltist Date: Mon, 31 Mar 2014 05:57:30 +0000 Subject: [PATCH] Add COFF libraries "utils.obj" atof,ftoa,random support for exponent, high accuracy, not normalized form of writing git-svn-id: svn://kolibrios.org@4721 a494cfbc-eb01-0410-851d-a64ba20cac60 --- .../develop/libraries/utils/trunk/_atof.inc | 300 +++++++++++++++++ .../develop/libraries/utils/trunk/_ftoa.inc | 305 ++++++++++++++++++ .../develop/libraries/utils/trunk/_rand.inc | 34 ++ .../develop/libraries/utils/trunk/build.bat | 2 + .../libraries/utils/trunk/example/demo.asm | 88 +++++ .../develop/libraries/utils/trunk/utils.asm | 64 ++++ 6 files changed, 793 insertions(+) create mode 100644 programs/develop/libraries/utils/trunk/_atof.inc create mode 100644 programs/develop/libraries/utils/trunk/_ftoa.inc create mode 100644 programs/develop/libraries/utils/trunk/_rand.inc create mode 100644 programs/develop/libraries/utils/trunk/build.bat create mode 100644 programs/develop/libraries/utils/trunk/example/demo.asm create mode 100644 programs/develop/libraries/utils/trunk/utils.asm diff --git a/programs/develop/libraries/utils/trunk/_atof.inc b/programs/develop/libraries/utils/trunk/_atof.inc new file mode 100644 index 0000000000..d8aa5c3d0b --- /dev/null +++ b/programs/develop/libraries/utils/trunk/_atof.inc @@ -0,0 +1,300 @@ +;-----------------------------------------------------------------------------+ +; Функция преобразования строки в вещественное число [ by ManHunter / PCL ] | +;-----------------------------------------------------------------------------| +; Параметры: | +; lpStr - указатель на исходную строку в формате ASCIIZ | +; lpResult - указатель на переменную-приемник значения | +; На выходе: | +; EAX = 1 - строка успешно преобразована | +; EAX = 0 - строка не может быть преобразована в число | +;-----------------------------------------------------------------------------+ +proc string2float lpStr:DWORD, lpResult:DWORD + ; Локальные переменные + locals + dot dd ? ; Указатель на дробную часть + exp dd ? ; Указатель на экспоненту + digit dd ? ; Цифра + endl + + pusha + + ; Проверка строки на валидность + mov [digit],1 + + mov [exp],0 + mov [dot],0 + mov esi,[lpStr] + ; Минус или плюс может быть только в начале + cmp byte [esi],'-' + je @f + cmp byte [esi],'+' + jne .loc_chk_loop +@@: + inc esi + + ; После знака не может быть нуля + cmp byte [esi],0 + je .loc_chk_error +.loc_chk_loop: + ; В строке должны быть цифр, экспонента и не более одной точки + lodsb + or al,al + jz .loc_chk_complete + cmp al,'e' + je .loc_chk_exp + cmp al,'E' + je .loc_chk_exp + cmp al,'.' + je .loc_chk_dot + cmp al,'0' + jb .loc_chk_error + cmp al,'9' + ja .loc_chk_error + jmp .loc_chk_loop + +.loc_chk_dot: + ; Точка в строке уже есть? + cmp [dot],0 + ; Строка имеет некорректный формат + jne .loc_chk_error + + ; Экспонента уже есть? + cmp [exp],0 + ; Строка имеет некорректный формат + jne .loc_chk_error + + ; Указатель на дробную часть + mov [dot],esi + + jmp .loc_chk_loop + +.loc_chk_exp: + ; Экспонента уже есть? + cmp [exp],0 + ; Строка имеет некорректный формат + jne .loc_chk_error + + ; Указатель на начало экспоненты + mov [exp],esi + + ; Сразу после экспоненты не может быть нуля + cmp byte [esi],0 + je .loc_chk_error + + ; После экспоненты может быть знак + cmp byte [esi],'-' + je @f + cmp byte [esi],'+' + jne .loc_chk_loop +@@: + inc esi + + ; Сразу после минуса не может быть нуля + cmp byte [esi],0 + je .loc_chk_error + + ; Проверить следующий символ + jmp .loc_chk_loop + +.loc_chk_error: + ; Строка не является числом + mov [digit],0 + jmp .loc_ret + +.loc_chk_complete: + ; Инициализация сопроцессора + finit + + ; Начальное значение числа + fldz + + ; Множитель и делитель + mov [digit],10 + fild dword [digit] + + ; Запись значений до запятой + mov esi,[lpStr] + + ; В начале строки минус? + cmp byte [esi],'-' + je @f + cmp byte [esi],'+' + jne .loc_before_dot +@@: + inc esi + ; Преобразование числа до запятой +.loc_before_dot: + lodsb + ; Конец строки? + or al,al + jz .loc_complete + + cmp al,'.' + je .loc_complete_before_dot + cmp al,'e' + je .loc_exp + cmp al,'E' + je .loc_exp + + ; Очередная цифра + sub al,'0' + movzx eax,al + mov [digit],eax + + ; Записать + fild dword [digit] + fxch st2 + fmul st0,st1 + fxch st2 + fadd st2,st0 + + ffree st0 ; Почистить стек + fincstp + + jmp .loc_before_dot + + ; Преобразование дробной части числа +.loc_complete_before_dot: + ; Дробная часть есть? + cmp [dot],0 + je .loc_complete_after_dot + + ; Экспонента есть? + cmp [exp],0 + je @f + + ; Указатель на начало экспоненты + mov esi,[exp] + jmp .loc_start_after_dot +@@: + ; Иначе перенести указатель на конец строки + xor ecx,ecx + dec ecx + xor eax,eax + mov edi,esi + repne scasb + + mov esi,edi + +.loc_start_after_dot: + std + dec esi + dec esi + + ; Дробная часть + fldz + fxch st1 +.loc_after_dot: + lodsb + ; Конец дробной части? + cmp al,'.' + je .loc_complete_after_dot + + ; Очередная цифра + sub al,'0' + movzx eax,al + mov [digit],eax + + ; Записать + fild dword [digit] + fadd st2,st0 + fxch st2 + fdiv st0,st1 + fxch st2 + + ffree st0 ; Почистить стек + fincstp + + jmp .loc_after_dot + +.loc_complete_after_dot: + ; Сбросить флаг направления + cld + + ffree st0 ; Почистить стек + fincstp + + ; Сложить дробную и целую часть + fadd st1,st0 + +.loc_exp: + ; Экспонента есть? + cmp [exp],0 + je .loc_complete + + ; Получить значение экспоненты + xor ecx,ecx + + mov esi,[exp] + ; В начале строки минус? + cmp byte [esi],'-' + je @f + cmp byte [esi],'+' + jne .loc_start_exp +@@: + inc esi +.loc_start_exp: + lodsb + or al,al + jz .loc_end_exp + + sub al,'0' + movzx eax,al + imul ecx,10 + add ecx,eax + + jmp .loc_start_exp +.loc_end_exp: + + or ecx,ecx + jz .loc_complete + + ffree st0 ; Почистить стек + fincstp + + mov [digit],10 + fild dword [digit] + + ; Делить или умножать? + mov esi,[exp] + cmp byte [esi],'-' + je .loc_exp_divide + +.loc_exp_multiple: + fmul st1,st0 + loop .loc_exp_multiple + jmp .loc_complete + +.loc_exp_divide: + fdiv st1,st0 + loop .loc_exp_divide + +.loc_complete: + ffree st0 ; Почистить стек + fincstp + + ; В начале строки минус? + mov esi,[lpStr] + cmp byte [esi],'-' + jne @f + + ; Изменить знак числа + fchs +@@: + ; Записать значение в ячейку памяти + mov eax,[lpResult] + ; Если требуется повышенная точность, то приемник + ; должен иметь размер QWORD, а следующую команду + ; надо заменить на fstp qword [eax] + fstp tword [eax] + + ; Успешное преобразование + mov [digit],1 +.loc_ret: + popa + + ; Результат преобразования + mov eax,[digit] + + ret +endp \ No newline at end of file diff --git a/programs/develop/libraries/utils/trunk/_ftoa.inc b/programs/develop/libraries/utils/trunk/_ftoa.inc new file mode 100644 index 0000000000..b4d1fb620d --- /dev/null +++ b/programs/develop/libraries/utils/trunk/_ftoa.inc @@ -0,0 +1,305 @@ +;-----------------------------------------------------------------------------+ +; Функция перевода вещественного числа в строку [ by ManHunter / PCL ] | +;-----------------------------------------------------------------------------| +; Параметры: | +; lpFloat - указатель на вещественное число TBYTE | +; lpResult - указатель на строку-приемник результата | +;-----------------------------------------------------------------------------+ + +proc FloatToString lpFloat:DWORD, lpResult:DWORD + ; Локальные переменные + local digits_count:DWORD + local old_cw:WORD + local new_cw:WORD + local saved_float:TBYTE + local tmp1 rb 11h + local tmp2 rb 11h + + ; Сохранить все регистры + pusha + + ; Указатель на строку-приемник + mov edi,[lpResult] + + ; Это ноль? + lea esi,[lpFloat] + cmp dword [esi],0 + jne loc_not_zero + cmp dword [esi+4],0 + jne loc_not_zero + cmp word [esi+8],0 + jne loc_not_zero + ; Записать в строку ноль + mov al,'0' + stosb + jmp loc_ret + +loc_not_zero: + ; Скопировать число в локальную переменную + push edi + mov esi,[lpFloat] + lea edi,[saved_float] + movsd + movsd + movsw + pop edi + ; Число отрицательное? + cmp dword [saved_float+6],0 + jge loc_not_signed + ; Привести число к абсолютному значению + and byte [saved_float+9],7Fh + ; Записать в строку минус + mov al,'-' + stosb + +loc_not_signed: + ; Проверить число на наличие дробной части и + ; подсчитать количество цифр в нем + fclex + ; Сохранить управляющее слово + fstcw [old_cw] + ; Установить управляющее слово + mov [new_cw],0000001001111111b + fldcw [new_cw] + lea esi,[saved_float] + fld tbyte [esi] + fld st + ; Выделить мантиссу и порядок + fxtract + fstp st + fldlg2 + ; Получить количество цифр в числе + fmulp st1,st + fistp [digits_count] + ; Если цифр больше 16, то число отображается в + ; нормализованном виде с мантиссой и экспонентой + cmp [digits_count],10h + jnb loc_not_integer + ; У числа есть дробная часть? + fld st + frndint + fcomp st1 + fstsw ax + test ah,01000000b + ; Да, отображать число с дробной частью + jz loc_not_integer + + ; Целое число без дробной части и экспоненты + lea eax,[tmp1] + fbstp [eax] + + ; Перевести BCD-число в строку + push edi + lea esi,[tmp1+8] + lea edi,[tmp2] + mov ecx, 9 +@@: + std + xor eax,eax + lodsb + cld + rol ax,12 + rol ah,4 + add ax,'00' + stosw + loop @b + pop edi + + ; Пропустить лидирующий ноль + mov eax,11h + mov ecx,[digits_count] + sub eax,ecx + inc ecx + lea esi,[tmp2+eax] + cmp byte [esi],'0' + jne @f + inc esi + dec ecx +@@: + ; Перенести полученное число из временного буфера + rep movsb + jmp loc_clear_stack + +loc_not_integer: + mov eax,10h + sub eax,[digits_count] + + ; Преобразовать число в целое до 16 разрядов + mov ecx,eax + cmp eax,0 + jge @f + neg eax +@@: + ; Для чисел больше 0 корректировка округления в сторону 0 + mov [new_cw],0000101001111111b + cmp ecx,0 + jge @f + mov [new_cw],0000011001111111b +@@: + ; Установить управляющее слово + fldcw [new_cw] + + ; Возвести 10 в степень количества цифр + fld [float2] + fld [float2] +@@: + fmul st,st1 + dec eax + cmp eax,1 + ja @b + + ; Почистить стек + fxch st1 + fstp st + + ; Если число меньше 0, то умножить, иначе разделить + cmp ecx,0 + jge @f + fdivp st1,st + jmp loc_rounded +@@: + fmulp st1,st + +loc_rounded: + ; Полученное значение меньше 1.0e16 ? + fcom [float1] + fstsw ax + test ah,1 + jz @f + fmul [float2] + dec [digits_count] +@@: + ; Целое число без дробной части и экспоненты + lea eax,[tmp1] + fbstp [eax] + + ; Перевести BCD-число в строку + push edi + lea esi,[tmp1+8] + lea edi,[tmp2] + mov ecx, 9 +@@: + std + xor eax,eax + lodsb + cld + rol ax,12 + rol ah,4 + add ax,'00' + stosw + loop @b + pop edi + + ; Числу требуется мантисса и экспонента? + lea esi,[tmp2+1] + mov ecx,[digits_count] + cmp ecx,-0Fh + jl loc_mantiss_and_exponent + cmp ecx,10h + jg loc_mantiss_and_exponent + + ; Заполнить дробную часть числа + inc ecx + cmp ecx,0 + jg @f + mov ax,'0.' + stosw + neg ecx + mov al,'0' + rep stosb + mov ecx,10h + jmp loc_fraction_filled +@@: + rep movsb + mov al,'.' + stosb + mov ecx,10h + sub ecx,[digits_count] + +loc_fraction_filled: + rep movsb + jmp @f + +loc_clear_fraction: + ; Удалить завершающие нули дробной части + dec edi +@@: + cmp byte [edi-1],'0' + jz loc_clear_fraction + cmp byte [edi-1],'.' + jnz @f + dec edi +@@: + jmp loc_clear_stack + +loc_mantiss_and_exponent: + ; Дробная часть мантиссы + movsb + mov al,'.' + stosb + movsd + movsd + movsw + ; Удалить завершающие нули дробной части +@@: + cmp byte [edi-1],'0' + jne @f + cmp byte [edi-2],'.' + je @f + dec edi + jmp @b +@@: + ; Символ и знак экспоненты + mov al,'e' + stosb + mov al,'+' + mov ebx,[digits_count] + cmp ebx, 0 + jge @f + mov al,'-' + neg ebx +@@: + stosb + + ; Значение экспоненты + mov eax,ebx + mov ecx,10 + mov ebx,4 +@@: + dec ebx + xor edx,edx + div ecx + add dl,'0' + mov [tmp1+ebx],dl + or ebx,ebx + jnz @b + + ; Пропустить лидирующие нули экспоненты + mov ecx,4 + lea esi,[tmp1] +@@: + lodsb + cmp al,'0' + jne @f + dec ecx + jmp @b +@@: + dec esi + rep movsb + +loc_clear_stack: + ; Восстановить управляющее слово + fldcw [old_cw] +loc_ret: + ; Окончание строки + mov al,0 + stosb + + ; Восстановить все регистры + popa + ret + +float1 dq 1.0e16 +float2 dq 10.0 + +endp \ No newline at end of file diff --git a/programs/develop/libraries/utils/trunk/_rand.inc b/programs/develop/libraries/utils/trunk/_rand.inc new file mode 100644 index 0000000000..8939300c0f --- /dev/null +++ b/programs/develop/libraries/utils/trunk/_rand.inc @@ -0,0 +1,34 @@ +;-----------------------------------------------------------------------------+ +; Функция генерации случайного числа в диапозоне 0..99999 | +;-----------------------------------------------------------------------------+ +; На выходе : eax - случайное число | +;-----------------------------------------------------------------------------+ +_random: + push edx ecx ebx + mov eax,ebx + or eax,eax + jnz @f + rdtsc + xor eax,edx + mov ebx,eax +@@: + xor edx,edx + mov ecx,127773 + div ecx + mov ecx,eax + mov eax,16807 + mul edx + mov edx,ecx + mov ecx,eax + mov eax,2836 + mul edx + sub ecx,eax + xor edx,edx + mov eax,ecx + mov ebx,ecx + mov ecx,100000 + div ecx + mov eax,edx + pop ebx ecx edx + ret +;-> diff --git a/programs/develop/libraries/utils/trunk/build.bat b/programs/develop/libraries/utils/trunk/build.bat new file mode 100644 index 0000000000..dbdf713611 --- /dev/null +++ b/programs/develop/libraries/utils/trunk/build.bat @@ -0,0 +1,2 @@ +@fasm -m 65536 utils.asm utils.obj +@kpack utils.obj \ No newline at end of file diff --git a/programs/develop/libraries/utils/trunk/example/demo.asm b/programs/develop/libraries/utils/trunk/example/demo.asm new file mode 100644 index 0000000000..c6eb4dda2f --- /dev/null +++ b/programs/develop/libraries/utils/trunk/example/demo.asm @@ -0,0 +1,88 @@ +;-----------------------------------------------------------------------------; +; =[ INIT ]= ; +;-----------------------------------------------------------------------------; +;; START: + call utils_init + +;-----------------------------------------------------------------------------; +; =[ USE ]= ; +;-----------------------------------------------------------------------------; + push fvalue ; value dt (XXXXX.XXXXX) + push fstring ; ASCIIZ string (rb 64) + call [_ftoa] ; convert + + push fstring ; ASCIIZ string ('XXXX.XXXXXX',0) + push fvalue ; value dt (?) + call [_atof] ; EAX: 0 - error, 1 - convert + + call [_random] ; EAX: random digit [0...99999] + +;-----------------------------------------------------------------------------; +; =[ LOAD ]= ; +;-----------------------------------------------------------------------------; +utils_init: + mov eax, 68 ; load DLL + mov ebx, 19 ; + mov ecx, utils_lib + int 0x40 + test eax, eax + jz utils_exit + + mov edx, eax ; initialize import + mov esi, utils_import ; import list +utils_loop: + lodsd + test eax, eax + jz utils_done + push edx +utils_find: + mov ebx, [edx] + test ebx, ebx + jz utils_exit ;import_not_found + push eax +@@: + mov cl, [eax] + cmp cl, [ebx] + jnz utils_next + test cl, cl + jz utils_found + inc eax + inc ebx + jmp @b +utils_next: + pop eax + add edx, 8 + jmp utils_find +utils_found: + pop eax + mov eax, [edx+4] + mov [esi-4], eax + pop edx + jmp utils_loop +utils_done: + ret +utils_exit: + mov eax, -1 + int 0x40 + +;-----------------------------------------------------------------------------; +; =[ DATA ]= ; +;-----------------------------------------------------------------------------; + fvalue dt -502556.267e600 ; dt ? + fstring db rb 100 ; '-15.246789',0 + + utils_lib db '/sys/lib/utils.obj',0 ; path + + align 4 + utils_import: + _ftoa dd ftoa + _atof dd atof + _random dd random + dd 0 + + ftoa db 'ftoa',0 + atof db 'atof',0 + random db 'random',0 +;-----------------------------------------------------------------------------; + + diff --git a/programs/develop/libraries/utils/trunk/utils.asm b/programs/develop/libraries/utils/trunk/utils.asm new file mode 100644 index 0000000000..831392c577 --- /dev/null +++ b/programs/develop/libraries/utils/trunk/utils.asm @@ -0,0 +1,64 @@ +;-----------------------------------------------------------------------------+ +; Library "utils" (c) Sergei Steshin (Akyltist) | +;-----------------------------------------------------------------------------+ +; Charset:DOS-866 Font:Courier New Size:9pt | +; compiler: FASM 1.69.31 | +; version: 0.1.0 | +; last update: 31/03/2014 | +; e-mail: dr.steshin@gmail.com | +; license: BSD | +;-----------------------------------------------------------------------------+ + +format MS COFF + +public EXPORTS + +section '.flat' code readable writable align 16 + +include '../../../../proc32.inc' +include '_ftoa.inc' +include '_atof.inc' +include '_rand.inc' + + +;-----------------------------------------------------------------------------+ +; float to ascii string | +;-----------------------------------------------------------------------------+ +ftoa: ; + mov ebx, dword [esp+4] ; out string + mov eax, dword [esp+8] ; in value + stdcall FloatToString,eax,ebx ; + ret 8 ; + + +;-----------------------------------------------------------------------------+ +; ascii string to float | +;-----------------------------------------------------------------------------+ +atof: ; + mov ebx, dword [esp+4] ; out <- value + mov eax, dword [esp+8] ; in -> string + stdcall string2float,eax,ebx ; + ret 8 ; + + +;-----------------------------------------------------------------------------+ +; returns a random integer in the range [ 0...99999 ] | +;-----------------------------------------------------------------------------+ +random: ; + call _random ; out <- eax random + ret ; + +;=============================================================================; +align 16 +EXPORTS: + dd szFtoa , ftoa + dd szAtof , atof + dd szRandom , random + dd 0 , 0 + + szFtoa db 'ftoa' ,0 + szAtof db 'atof' ,0 + szRandom db 'random' ,0 + +section '.data' data readable writable align 16 +