How to sleep in a 16-bit x86 build?

I want to stop execution for about 0.1 second, regardless of the processor clock speed. The code must run directly from the boot device, so it should not use DOS interrupts.

I am currently using int 15h , but this seems to contradict the beeps that I modulate with channel 2 PIT. I heard about channel 0, but I don't know how to set it.

Accuracy is not so important, but it should work on old and modern computers at the same speed. Therefore, simply loop instructions are not an option.

The sound signal and sleep is just a bunch of macros for changing the frequency and turning the speaker on and off. The beep does not stop if I cause a sleep right before the beepoff .

Here are the beep macros:

 %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 

and dream:

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

I am using NASM assembler.

This is not a duplicate. How to create a sleep function in the x86 16-bit MASM assembly? because it is for building without iron outside of Windows or DOS.

+5
source share
1 answer

A programmable interval timer is the way to go. If you will only deal with new systems, learn HPET. There are a few things to know for PIT. Firstly, to configure it, you need to use port 0x43 as the control / command port to set the zero channel timer. The byte we want to send is a bitmap field:

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

The channel will be cleared to select the zero channel.

The RW model can be 1-LSB, 2-MSB or 3-LSB, followed by an MSB. We want both bits to be (bit pattern 3, 011), because we need to send a 16-bit value (LSB, then MSB)

For channel mode, we need a square wave. This is a bit pattern from 3 (011)

We want to send a 16-bit divider for the counter, not the BCD value, so the low bit is cleared.

This gives us: 000110110 in binary format or 0x36 in hexadecimal format. Now we have installed it:

 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 

At this point, you need to decide whether you will respond to the interrupt (IRQ 0) or just want to read the timer. I will point you to this excellent link to OSDev, which has a brilliant entry on both code examples.

+3
source

Source: https://habr.com/ru/post/1246860/


All Articles