2016-04-11 2 views
5

Я хочу остановить выполнение примерно 0,1 секунды, независимо от тактовой частоты процессора. Код должен запускаться непосредственно с загрузочного устройства, поэтому он не должен использовать прерывания DOS.Как спать в сборе 16 бит x86?

В настоящее время я использую int 15h, но это, похоже, противоречит звуковым сигналам. Я модулирую канал 2 PIT. Я слышал о канале 0, но я не знаю, как это настроить.

Точность не так важна, однако она должна работать на старых и современных компьютерах с одинаковой скоростью. Так что просто инструкции по циклу не являются опцией.

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

Вот гудок макросы:

%macro beepinit 0 
    mov al, 182 
    out 43h, al 
%endmacro 

%macro beepfreq 0 
    out 42h, al 
    mov al, ah 
    out 42h, al 
%endmacro 

%macro beepon 0 
    in al, 61h 
    or al, 00000011b 
    out 61h, al 
%endmacro 

%macro beepoff 0 
    in al, 61h 
    and al, 11111100b 
    out 61h, al 
%endmacro 

и сон один:

%macro sleep 2 
    push dx 
    mov ah, 86h 
    mov cx, %1 
    mov dx, %2 
    int 15h 
    pop dx 
%endmacro 

Я использую ассемблер NASM.

Это не дубликат How can I create a sleep function in 16bit MASM Assembly x86?, потому что этот вариант предназначен для сборки без сбоев вне Windows или DOS.

+1

Я бы предложил сделать заголовок «Как спать в 16-битной сборке x86 с шестью металлами», чтобы отличить вопросы от OS-зависимого. Возможно, указывая в вопросе о том, как вы пытались использовать int 15h, этот вопрос не будет слишком широким (это граница в его текущей форме). –

+0

@PascalCuoq Хорошо, я немного его отредактировал. –

+0

Связанный: http://stackoverflow.com/a/1862232/509868 – anatolyg

ответ

3

Программируемый таймер интервалов - это путь. Если вы будете заниматься только новыми системами, изучите HPET. Для PIT есть несколько вещей, которые нужно знать. Во-первых, чтобы настроить его, вам нужно использовать порт 0x43 в качестве порта управления/команды для настройки таймера нулевого канала. Байт, который мы хотим отправить туда немного отображается поле:

7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 
+----------------------------------------------+ 
| Channel | RW Mode | Channel Mode | BCD?| 
+----------------------------------------------+ 

канал будет сброшен для выбора нулевого канала.

Модель RW может быть 1-LSB, 2-MSB или 3-LSB, за которой следует MSB. Мы хотим, чтобы оба бита включались (битовая диаграмма 3, 011), потому что нам нужно отправить 16-битное значение (LSB, затем MSB)

Для режима канала нам нужна прямоугольная волна. Это бит-шаблон 3 (011)

Мы хотим отправить 16-разрядный делитель для счетчика, а не значение BCD, поэтому бит младшего разряда очищается.

Это дает нам: 000110110 в двоичном формате или 0x36 в шестнадцатеричном формате. Теперь мы устанавливаем его:

mov al, 0x36 ; 0x36 from our work above 
out 0x43, al ; Send that byte to the control port 

mov ax, 11931 ; The timer ticks at 1193182. 100hz would be 1193182/11931 
out 0x40, al ; send low byte 
out 0x40, ah ; send high byte 

На этом этапе вам нужно решить, если вы собираетесь реагировать на прерывание (IRQ 0) или просто хотите прочитать таймер. Я укажу вам на this excellent reference на OSDev, который имеет блестящую запись на обоих примерах кода.

+0

Проблема в том, что примерный код OSDev сделан для 32-разрядной сборки. –

+0

... почему это проблема? Достаточно просто перевести это на 16 бит или, альтернативно, оставить BIOS прерывания и перейти в защищенный режим. –

+0

Например, с кодом, который я разместил здесь (все 16 бит), вы можете либо периодически читать нулевой канал, чтобы получить счет перехода, либо настроить ISR для IRQ 0. Ничто действительно не меняется между 32 и 16-битным кодом, насколько это возможно это идет за исключением размера адресов. –

Смежные вопросы