Как я могу создать функцию сна в блоке MASM на 16 битов x86?

3 байта:

label:
  pusha
  jmp label

Обновление

Согласно (старая?) Документация Intel (?) , это - также 3 байта:

label:
  call label

10
задан Ciro Santilli 新疆改造中心法轮功六四事件 7 November 2015 в 19:32
поделиться

4 ответа

Фактически вы можете использовать прерывание ROM BIOS 1Ah, функция 00h, 'Read Current Счетчик часов ». Или вы можете читать dword по адресу $ 40: $ 6C, но вы должны обеспечить атомарное чтение. Он увеличивается в MS-DOS примерно с частотой 18,2 Гц.

Для получения дополнительной информации прочтите: Часы DOS

3
ответ дан 3 December 2019 в 17:20
поделиться

Ну, тогда. Старый стиль, непостоянный, потребляющий много энергии цикл задержки, который заставит другие потоки работать медленнее, будет выглядеть так:

       delay equ 5000

top:   mov ax, delay
loopa: mov bx, delay
loopb: dec bx
       jnc loopb
       dec ax
       jnc loopa

       mov ah,2
       mov dl,'A'
       int 21
       jmp top

Задержка квадратична по отношению к константе. Но если вы воспользуетесь этим циклом задержки, где-нибудь в мире умрет молодой невинный котенок.

2
ответ дан 3 December 2019 в 17:20
поделиться

Я не тестировал этот код, но концепция должна работать ... Сохранять / восстанавливать регистр не обязательно! Внимательно проверьте код!

DelayProcedure:
    push  es                      //Save es and load new es
    mov   ax, 0040h
    mov   es, ax
//Pseudo atomic read of 32 bit DOS time tick variable
PseudoAtomicRead1:
    mov   ax, es:[006ch]
    mov   dx, es:[006eh]
    cmp   ax, es:[006ch]
    jne   PseudoAtomicRead1
//Add time delay to dx,ax where smaller is faster and 18 is close to 1 second
    add   ax, 3
    adc   dx, 0
//1800AFh is last DOS time tick value so check day overflow
    mov   cx, ax
    mov   bx, dx
//Do 32 bit subtract/compare
    sub   cx, 00AFh
    sbb   dx, 0018h
    jbe   DayOverflow
//Pseudo atomic read of 32 bit DOS time tick variable
PseudoAtomicRead2:
    mov   cx, es:[006ch]
    mov   bx, es:[006eh]
    cmp   cx, es:[006ch]
    jne   PseudoAtomicRead2
NotZero:
//At last do 32 bit compare
    sub   cx, ax
    sbb   bx, dx
    jae   Exit
//Check again day overflow because task scheduler can overjumps last time ticks
    inc   bx                //If no Day Overflow then bx = 0FFh
    jz    PseudoAtomicRead2
    jmp   Exit
DayOverflow:
//Pseudo atomic read of 32 bit DOS time tick variable
PseudoAtomicRead3:
    mov   ax, es:[006ch]
    mov   dx, es:[006eh]
    cmp   dx, es:[006ch]
    jne   PseudoAtomicRead3
//At last do 32 bit compare
    sub   ax, cx
    sbb   dx, bx
    jb    PseudoAtomicRead3
Exit:
    pop   es                      //Restore es
    ret
2
ответ дан 3 December 2019 в 17:20
поделиться

Это невозможно сделать в чистом MASM. Все старые приемы для установки фиксированной задержки работают в предположении, что вы полностью контролируете машину и являетесь единственным потоком, работающим на ЦП, так что если вы подождете 500 миллионов циклов, ровно 500000000 / f пройдут секунды (для процессора с частотой f ); это будет 500 мс для процессора с тактовой частотой 1 ГГц.

Поскольку вы работаете в современной операционной системе, вы разделяете ЦП со многими другими потоками (среди них, ядро ​​- что бы вы ни делали, вы не можете получить приоритет над ядром!), поэтому ожидание 500 миллионов циклов только в вашем потоке будет означать, что в реальном мире пройдет более 500 миллионов циклов. Эту проблему нельзя решить одним только кодом пользовательского пространства; вам понадобится сотрудничество ядра.

Надлежащий способ решить эту проблему - это посмотреть, какая функция Win32 API приостановит ваш поток на указанное количество миллисекунд, а затем просто вызвать эту функцию. Вы должны иметь возможность делать это прямо из сборки, возможно, с дополнительными аргументами для вашего компоновщика. Или для выполнения этой функции может быть системный вызов ядра NT (у меня очень мало опыта работы с системными вызовами NT, и, честно говоря, я понятия не имею, как выглядит таблица системных вызовов NT, но функция сна - это то, что я мог бы ожидайте увидеть). Если доступен системный вызов, тогда выполнение прямого системного вызова из сборки, вероятно, будет самым быстрым способом сделать то, что вы хотите; это также наименее переносимый (но тогда вы пишете ассемблер!).

Правка : Глядя на таблицу системных вызовов ядра NT , похоже, нет никаких связанных вызовов для сна или получения даты и времени (как в исходном коде), но есть несколько системных вызовов для установки и запроса таймеров. Вращение, пока вы ждете, пока таймер достигнет желаемой задержки, - одно из эффективных, хотя и не изящных решений.

t кажутся любыми вызовами, связанными со сном или получением даты и времени (как в исходном коде), но есть несколько системных вызовов для установки и запроса таймеров. Вращение, пока вы ждете, пока таймер достигнет желаемой задержки, - одно из эффективных, хотя и не изящных решений.

t кажутся любыми вызовами, связанными со сном или получением даты и времени (как в исходном коде), но есть несколько системных вызовов для установки и запроса таймеров. Вращение, пока вы ждете, пока таймер достигнет желаемой задержки, - одно из эффективных, хотя и неэлегантных решений.

11
ответ дан 3 December 2019 в 17:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: