Рассылка закрыта
При закрытии подписчики были переданы в рассылку "О карьере и профессиональном развитии IT-специалистов" на которую и рекомендуем вам подписаться.
Вы можете найти рассылки сходной тематики в Каталоге рассылок.
| ← Сентябрь 2003 → | ||||||
|
1
|
2
|
3
|
4
|
6
|
7
|
|
|---|---|---|---|---|---|---|
|
8
|
9
|
10
|
11
|
12
|
13
|
14
|
|
15
|
16
|
17
|
18
|
19
|
20
|
21
|
|
22
|
24
|
25
|
26
|
27
|
28
|
|
|
29
|
30
|
|||||
Статистика
+11 за неделю
Низкоуровневое программирование для дZeнствующих #0041
| Информационный Канал Subscribe.Ru |
# Пролог
|
||||||||||||||||||||||||||||||||
| отвђт | Сообщенiе |
animator
Воин дзена |
Дата: Авг 29, 2003 13:22:39 Скажите пажалуйста как програмно выдернуть сетевой шнур из сетевой платы под Win2000Prof? |
|
pas
Воин дзена |
Дата: Авг 29, 2003 14:29:45 Скажите пажалуйста как програмно выдернуть сетевой шнур из сетевой платы под Win2000Prof? ИМХО програмно под любой ОС ни как, только подойти в шнуру и ручками его выдернуть. |
|
Sk. Inc.
Воин дзена |
Дата: Авг 29, 2003 19:23:12 Очень просто и даже можно двумя вариантами: 1) Запрограммировать сетевой шнур на выскакивание из сетевой платы 2) Запрограммировать сетевую плату на выплёвывание шнура Какой способ проще - решать тебе ;-) |
|
DaemoniacaL
Воин дзена |
Дата: Авг 30,
2003 01:29:11 А можно запрограммировать собачку AIBO пусть подбегает и выдергивает когда надо :) |
|
KiNDeR
Воин дзена |
Дата:
Авг 30, 2003 01:40:59 Во, Идея. Берем ленточный принтер, веревку. Один конец веревки привязываем к барабану принтера, другой к кабелю. Пишем прогу которая посылает в принтер сигнал. Барабан вращается, веревка натягивается, кабель выдергивается... Все довольны, все медитируют... |
|
Quantum
Воин дзена |
Дата: Авг 30,
2003 01:57:15 KiNDeR Ещё проще: Привязываем верёвочку к CD; Программно открываем CD :) ЗЫ: А как воткнуть этот шнур обратно? |
|
KiNDeR
Воин дзена |
Дата:
Авг 30, 2003 01:58:24 Quantum Воткнуть. Вместо веревки используем проволку...или стальной прут. |
|
DaemoniacaL
Воин дзена |
Дата: Авг 30,
2003 02:12:11 Сделать переходник RJ-45<>RJ-45 внутрь встаить 8-контактное реле, управлять с какого-нить порта. |
|
volodya
[ HI-TECH ] |
Дата:
Авг 30, 2003 05:01:37 Наверное, как-то можно это сделать. Написать драйвер, который бы долбал бы драйвер платы (я так понимаю, в терминологии Windows это будет мини-драйвер), и усе :))) Работы на пару месяцев... :) |
Edmond / HI-TECH
/\ & ()
(алгоритмы и оптимизация)
Извечное преобразование слов машины в слова людей
Сегодня я решил покончить с клюбом читателей WASM.RU, и плавно перенести его в клуб творителей. Это значит, что у Вас есть теперь повод поучаствовать в чём-то достаточно серьёзном. С другой стороны, последнее время я заметил насколько поднимает жизненный тонус оптимизация кода, и решил, что если совместить очень приятное с очень полезным – получится рулез во всех смыслах этого слова.
Перед вами код четырёх функций преобразования. Это не просто функции, а так называемые Элементарные контекстные функции.
Многие из нас привыкли, что преобразование числа в строку осуществляется
отдельной функцией. Да, с точки зрения достижение максимума скорости
такой подход был
бы верен, однако с точки зрения совершенства архитектуры – нет. Перед вами
не сами
функции перевода строки в число или наоборот. Сами по себе переводить они
не могут, ибо не учитывают ошибок, которые могут быть допущены при
конвертировании
(а если учитывают, то список этих ошибок мал).
На основе этих элементарных контекстных функций могут быть основаны сложнейшие
процедуры, начиная от банального перевода строк в числа и наоборот, заканчивая
конвейерной обработкой данных в компиляторах ets. Интерфейсы этих функций
построены таким образом, чтобы их было легко использовать как при преобразовании
UNICODE,
так и ANSI строк.
Вам предлагается оптимизировать их по скорости либо по размеру, соблюдая
жёсткие рамки интерфейса на входе и выходе функций. Однако вы можете:
- Менять алгоритм
- По-другому переплетать код
Ваши предложения и примеры мы ждём на форуме WASM.RU. Либо, если по каким-то причинам вам не доступен форум, я буду рад вашим замечаниям по email Edmond@wasm.ru
Лучшие варианты по размеру и скорости будут опубликованы в качестве первых релизов проекта ULIB/TplOut в феврале 2004 года.
;; Модуль x_to_x
;; Базовая версия
;; (c) Edmond/HI-TECH
;; ####################### DATA #####################################
.data
CONSTANT_1999999Ah dd 1999999Ah
CONSTANT_1000000000 dd 1000000000
CONSTANT_10 dd 10
CONSTANT_5 dd 5
.code
;; ######################## CODE ####################################
;; FUN::ВСDInt32_to_Str
;;------------------------------
; CONV::ASMCALL
; FORMALS::
; int32 = ecx type:dword
; - целое число, которое должно быть преобразовано в строку
; buffer = edi type:pointer
; - указатель на буфер, в который должна быть помещена строка.
; RET::
; Функция возвращает строку в буфер, и edi указывает на последнюю
; секцию символов, помещённые в буфер.
; Регистр ebx содержит последнюю секцию, помещённую в буфер.
;
; DPN::
; Элементарная функция, которая преобразовывает число
; в BCD строку
; в обратном виде (то есть от младшего разряда к старшему)
;------------------------------
; ALG:
Comment #
Функция делит число на 10, а остатоки от деления состовляют строку
Здесь функция имеет два цикла:
1. Большой цикл
2. Малый цикл
В малом цикле результат выполнения функции
накапливается в регистре ebx
И в конце цикла помещается в строку.
#
;; ==================================================================
Int_to_Str@@Div10 MACRO
;; %%%%%%%%%%%%%%%%%%%%%%%%%%
Comment #
Макро, который скрывает код для деления числа на 10
А так же код, который участвует в малом цикле
#
; USE:
; eax - текущее число для mul
; ebx - аккумулятор для собрания 4 символов строки
; ecx - число x
; edx - число x/10
;; %%%%%%%%%%%%%%%%%%%%%%%%%%
mul CONSTANT_1999999Ah
;; Сохранение результата для последующих операций
mov eax,edx
;; Умножение eax на 10
add eax,eax
lea eax,[eax+eax*4]
;; Получаем остаток в ecx
sub ecx,eax
;; Помещаем в eax следующее значение x/10,
;; которое хранилось в edx
mov eax,edx
;; результат в ebx
shrd ebx,ecx,8
;; Помещаем в ecx текущее число
mov ecx,eax
ENDM
;; ===========================================
BCDInt32_to_Str proc
;; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Comment #
::Алгоритм.
Функция выполняет последовательное деление
исходного числа на число 10.
Остатки при деление и есть десятичными разрядами числа.
::Особенности алгоритма
Деление выполняется при помощи умножения с переполнением.
#
; USE:
; eax - текущее число для mul
; ebx - аккумулятор для собрания 4 символов строки
; ecx - число x
; edx - число x/10
;; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;; +++++++ Большой цикл +++++++++++++++++++++++++
ALIGN 16
@@:
mov eax,ecx
xor ebx,ebx
;;++++++++++++++++++++++++++++++++++++++++++++++++
comment /-------------
Точки входа BCDInt32_to_Str_xx существуют
для возможности использовать
данный код
более гибче в других функциях
---------------------/
BCDInt32_to_Str_1::
Int_to_Str@@Div10
BCDInt32_to_Str_2::
Int_to_Str@@Div10
BCDInt32_to_Str_3::
Int_to_Str@@Div10
BCDInt32_to_Str_4::
Int_to_Str@@Div10
;;++++++++++++++++++++++++++++++++++++++++++++++++
mov eax,ebx
;; (Если вы добавите эту строчку вы получите ASCII строку)
;; -- add eax,30303030h --
test ecx,ecx
stosd
jnz short @B
;; +++++++ Большой цикл +++++++++++++++++++++++++
ret
BCDInt32_to_Str endp
;; #############################################################
;; #############################################################
;; FUN::BCDInt64_to_Str
;;------------------------------
; CONV::ASMCALL
; FORMALS::
; int64 = edx:eax type:qword
; - целое число, которое должно быть преобразовано в строку
; buffer = edi type:pointer
; - указатель на буфер, в который должна быть помещена строка.
; RET::
; Функция возвращает число в буфер, регистр edi указывает
; на последнию секцию
; символов, помещённые в буфер, а в регистре ebx -- их содержит.
; DPN::
; Элементарная функция, которая преобразовывает число int6
; 4 в BCD строку,
; в обратном виде (то есть от младшего разряда к старшему).
;------------------------------
; ALG:
Comment #
Функция разбивает 64-битное число на два,
и использует участки кода функции BCDInt32_to_Str для того,
чтобы преобразовать части числа.
Особенностью работы функции является запись 32 битного результата
в память.
Поскольку функция BCDInt32_to_Str возвращает результат выполнения
в регистре ebx и результат может не полностью помещатся
в регистр ebx, то функция следит за тем,чтобы следующий
результат BCDInt32_to_Str продолжил заполнения этого регистра.
#
;; ==================================================================
BCDInt64_to_Str proc
;; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Comment #
#
; USE:
; all
;; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;; 1. При помощи команды div CONSTANT_1000000000
;; нельзя делить числа
;; большие FFFFFFFFFFFFF, поэтому это следует учесть.
test edx,0f0000000h
jnz @F
;; 2. В том случае, если условие не выполнилось,
;; число можно разделить при помощи
;; Одной команды DIV
start:
div CONSTANT_1000000000
push eax
mov ecx,edx
call BCDInt32_to_Str
;; 3. !!!
;; После вызова этой функции, регистр ebx хранит последние
;; помещённые в память
;; четыре байта. При этом доказано, что какое бы на входе
;; ни было число,
;; ebx заполнен только младшим разрядом, то есть,
;; ebx = 000000xxh
;; Таким образом, чтобы последующие числа не были разорваны нулями
;; мы корректируем ebx, так, как будто уже выполнился
;; первая часть кода в BCDInt32_to_Str
;; И передаём управление не на начало процедуры BCDInt32_to_Str
;; а на BCDInt32_to_Str_2
;; Эти операции выполняет код
;; Помещаем старшую числа для преобразования
pop ecx
sub edi,4 ;; Уменьшаем edi,
;; чтобы число записалось вместо старого
mov eax,ecx
ror ebx,8
;; Я делаю jmp вместо call, и управление вернётся к функции,
;; которая вызвала данную
jmp BCDInt32_to_Str_2
;; 4. В том случае, если число больше значения FFFFFFFFFFFFF
;; Алгоритм усложняется
;; 4.1 Сперва мы покомпонентно делим число на 1000000000
@@: mov ecx,eax
mov eax,edx
xor edx,edx
div CONSTANT_1000000000
;; После этой команды в eax - остаётся самый старший разряд числа
;; Мы сохраняем его в стеке, так как он понадобится позднее.
push eax
xchg ecx,eax
div CONSTANT_1000000000
;; 4.2 После этой команды, в регистре edx окажется младшая
;; часть числа,
;; которую можно перевести в строку функцией BCDInt32_to_Str
;; Сохраняем старшую часть
push eax
;; В ecx - параметр функции
mov ecx,edx
call BCDInt32_to_Str
;; 4.3 Восстанавливаем из стека сохранённые части 64-bits числа
;; в edx:eax
pop eax
pop edx
div CONSTANT_1000000000
;; 4.4 Аналогично, теперь мы имеем разбитое на две части число.
;; Старшуй часть, которая в eax, сохраняем на потом,
;; а младшую (edx), переводим
;; в строку.
push eax
Comment /------------------
Пара команд
sub edi,4
ror ebx,8
Находятся здесь потому как они корректируют контекст
после выполнения функции BCDInt32_to_Str.
При этом доподлинно известно, что после выполнения этой функции
ebx заполняется только младшим разрядом. ebx = 000000xxh
Чтобы строка BCD не разделялась нулями, которых нет,
мы корректируем значения ebx и edi, и вызываем выполнение
с точки входа BCDInt32_to_Str_2
-------------------/
sub edi,4
mov ecx,edx
mov eax,edx
ror ebx,8
call BCDInt32_to_Str_2
Comment /------------------
Пара команд
sub edi,4
shl ebx,16
Находятся здесь потому, так как они корректируют контекст
после выполнения функции BCDInt32_to_Str_2.
При этом доподлинно известно, что после выполнения этой функции
ebx заполняется только двумя младшими байтами: ebx = 0000xxxxh.
Чтобы строка BCD не разделялась нулями, которых нет,
мы корректируем значения ebx и edi, и вызываем выполнение
с точки входа BCDInt32_to_Str_3
-------------------/
;; Помещаем старшую числа для преобразования
pop ecx
;; Уменьшаем edi
sub edi,4
;; Контекст для точки вызова
mov eax,ecx
shl ebx,16
;; после этого ebx = xxxx0000h
;; Я делаю jmp вместо call, и управление вернётся к функции, которая
;; вызвала данную
jmp BCDInt32_to_Str_3
BCDInt64_to_Str endp
;; ##################################################################
;; Варианты функций для непроверенной не BCD строки
IF not CM$__string_check
;; ##################################################################
;; FUN::Str_to_Int32
;;------------------------------
; CONV::ASMCALL
; FORMALS::
; pbuffer = esi type:offset buffser
; - буффер строки ASCII заканчивающийся нулём
; RET::
; int32 = edx
; - число
; errcode = eax
; - код ошибки. Если ошибок не было errcode = 0
; pbuffer = esi
; - указывает на последний символ,
; который был прочитан функцией.
; DPN::
; Функция конвертирует строку ASCII в число int32. В случае
; ошибки, функция возвращает ненулевое значение в eax, которое
; равно символу, не соответствующиму ASCII цифрам.
; Таким образом, не обязательно, чтобы строка завершалась нулём.
; Но вызвавшая функция сама должна оценить ситуацию.
;
;------------------------------
; ALG:
Comment # Алгоритм
Функция считывает каждый символ из строки.
Преобразовывает ASCII символ в BCD (ASCII-30)
и запоминает его (edx).
При каждом следующем считывании она
увеличивает запомненное число на 10,
и прибавляет к нему новое, взятое из строки.
#
;; ==================================================================
Str_to_Int32 proc
;; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Comment #
#
; USE:
; eax, edx
;; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
xor eax,eax
xor edx,edx
ALIGN 16
@@: ; ------- Цикл ------------
lodsb
sub al,30h
;; Если меньше -- конец
jb short @F
cmp al,9
ja short @F
lea edx,[edx+edx*4]
lea edx,[eax+edx*2]
jmp short @B
@@:
add al,30h
ret
Str_to_Int32 endp
;; ##################################################################
;; ##################################################################
;; FUN::Str_to_Int64
;;------------------------------
; CONV::ASMCALL
; FORMALS::
; buffer = esi type:pointer
; - указатель на строку, заканчивающююся нулём.
; RET::
; int64 = edx:eax
; - число
; ecx - Последний символ, обработанный функцией
; esi - Указатель на последний символ,
; обработанный функцией
; DPN::
; Функция преобразовывает строку в INT64 число.
;;------------------------------
; ALG:
Comment # Алгоритм
Перевод осуществляется в два этапа.
Сперва переводится в число старшая часть числа
После младшая
И в конце результат корректируется.
Основная идея разделения перевода строки в 64 число,
состоит в следующем:
1. Мы переводим строку в число, пока число
не превысит крайнего значения 32-bits
2. Результат запоминается
3. Переводится оставшая (младшая) часть числа,
и при этом подсчитывается количество
разрядов, вошедшее в это число.
4. Основываясь на колличестве разрядов,
старшая половина корректируется
и суммируется с младшей частью.
#
;; ==================================================================
Str_to_Int64 proc
;; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Comment #
#
; USE:
; eax,edx,ecx
;; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
xor eax,eax
xor edx,edx
mov ecx,eax
;; ECX будет содержать число 10*n,
;; где n - число разрядров прошедших к анализу.
inc ecx
ALIGN 16
@@: ; ------- Цикл ------------
lodsb
sub al,30h
;; Если меньше -- конец
jb short endproc
cmp al,9
ja short endproc
lea edx,[edx+edx*4]
lea edx,[eax+edx*2]
;; Если сумматор превысит это значение,
;; значит преобразование старшей части завершено
Str_to_Int64_next::
;; ffffffffh/ah = 19999999h
cmp edx,19999999h
jna @B
@@:
;; Когда закончилось преобразование
;; старшей части запоминаем её в стеке
push edx
xor edx,edx
@@: ; ------- Цикл ------------
lodsb
sub al,30h
;; Если меньше -- конец
jb short @F
cmp al,9
ja short @F
shl ecx,1
;; edx = edx*10+eax
lea edx,[edx+edx*4]
lea edx,[eax+edx*2]
;; ecx = ecx*10 (shl ecx, 1 уже была выше)
lea ecx,[ecx+ecx*4]
;; Следует следить за тем, чтобы сумматор множетеля разрядности
;; не переполнился
cmp ecx,1000000000
jae short above_19999999h
jmp @B
@@:
;; Преобразование младшей части закончено.
;; В стеке была сохранена старшая часть числа
;; Помещаем её в eax.
pop eax
;; Процедура корректирования результата преобразований
;; младшей и старшей части.
Str_to_Int64_correct::
correct:
;; Контекст
;; eax - старшая часть числа
;; edx - младшая часть числа
;; ecx - множитель
;; 1. Сохраняем в стеке младшую часть.
push edx
mul ecx
;; После этой команды в edx:eax хранится 64-bits число
;; Теперь к нему нужно прибавить оставшуюся часть результата,
;; которая находится в стеке
pop ecx
;; edx:eax = edx:eax+ecx
add eax,ecx
adc edx,0
;; Последний символ возвращается в cl
xor ecx,ecx
mov cl, byte ptr [esi-1]
ret
above_19999999h:
;; Управление приходит сюда, только в том случае,
;; если число слишком
;; большое для команд lea и поэтому нужно воспользоваться
;; другим алгоритмом.
;; Контекст:
;; edx - содержит текущее число, которое больше, чем 19999999h
;; ecx - содержит число переведённых разрядов
;; в стеке лежит старшая часть числа.
;; Поскольку теперь уже всё равно придётся иметь дело
;; с умножением 64 битного
;; числа, мы делаем приведение
pop eax ;; eax = старшая часть числа
call correct
;; Теперь edx:eax - содержат 64-bits текущее число.
mov ecx,eax
;; Прибавляем последний разряд
xor eax,eax
lodsb
sub al,30h
;; Если меньше -- конец
jb short @F
cmp al,9
ja short @F
;; старшая часть числа * 10
;; младшая * 10
push eax
mov eax,ecx
mov ecx,edx
shl ecx,1
mul CONSTANT_10
lea ecx,[ecx+ecx*4]
add edx,ecx
pop ecx
;; edx:eax = edx:eax + ecx (ecx = последний символ - 30h)
add eax,ecx
adc edx,0
;; Преобразование законченно
xor ecx,ecx
mov cl,[esi]
inc esi
ret
;; Управление приходит на эту метку,
;; если мы вернулись при преобразовании последнего символа
@@:
add al,30h
xchg ecx,eax
ret
;; Управление приходит сюда, если мы вернулись из первого цикла.
endproc:
xor eax,eax
mov al,byte ptr [esi-1]
mov ecx,eax
mov eax,edx
xor edx,edx
ret
Str_to_Int64 endp
;; ##################################################################
# Эпилог
| …. И каждое начало Сентября вы будете чувствовать необычайный подъём сил. Кто знает, возможно, точно так же как чувствовал это Александр Сергеевич в момент наступления осени. Хотя он был поэт, а не программист. Однако сколько же программистов по имени Александ :)))) |
###########################################################################
Оригинальное всТупление
|
Edmond / HI-TECH
|
|
------------- |
||
###########################################################################
| Рассылка составлена HI-TECH GROUP 02 сентября 2003 года. |
(c) HI-TECH 2000-2003
| http://subscribe.ru/
E-mail: ask@subscribe.ru |
Отписаться
Убрать рекламу |
| В избранное | ||
