VOGONS


First post, by PalMusicFan

User metadata
Rank Newbie
Rank
Newbie

In order to get an accurate and stable clock to play OPL2 BGM, I need to reprogram the 8254 to obtain a higher frequency int 8h.

However, after consulting a lot of information, it seems that this is quite cumbersome for DJGPP.

PCTIMER (https://technology.chtsai.org/pctimer/) seems to fully meet my requirements. After dealing with some minor issues, it compiled successfully.

However, I found that although the program seemed to be running, the real-mode handler named rm_new8h was not called at all, and the original BIOS handler was still called 1:1.

What is the problem? Thank you so much!

Reply 1 of 7, by zyzzle

User metadata
Rank Member
Rank
Member

May we test your compiled DJGPP binary? Or were you not able to compile the DJGPP version, and only got the real-mode timer compiled successfully?

Reply 2 of 7, by PalMusicFan

User metadata
Rank Newbie
Rank
Newbie
zyzzle wrote on Today, 11:29:

May we test your compiled DJGPP binary? Or were you not able to compile the DJGPP version, and only got the real-mode timer compiled successfully?

OK, here is the sourcecode and the binary.

EDIT: testflag is always 0, which means the real mode handler is never called. Also, the time is very fast, which means the BIOS handler is still there.

Reply 3 of 7, by BloodyCactus

User metadata
Rank Oldbie
Rank
Oldbie

your all sorts of convoluted. I dont think you need to do anything to the RM handler, hooking the PM handler should be enough (it is in watcom from what I remember).

The best thing to do is, keep count of your ticks, then when the program ends, set the date+time (which wont have changed) plus your ticks. This is the best way, because if you chain into the old handler you never know how expensive thats going to be (how long it will take), and you dont want to miss your own interrupts or get your behind in frame generation.

you also dont need the whole counter_reset thing. just inc your ticks++ and trigger EOI. keep your timer as short as possible.

--/\-[ Stu : Bloody Cactus :: [ https://bloodycactus.com :: http://kråketær.com ]-/\--

Reply 4 of 7, by PalMusicFan

User metadata
Rank Newbie
Rank
Newbie
BloodyCactus wrote on Today, 12:16:

your all sorts of convoluted. I dont think you need to do anything to the RM handler, hooking the PM handler should be enough (it is in watcom from what I remember).

The best thing to do is, keep count of your ticks, then when the program ends, set the date+time (which wont have changed) plus your ticks. This is the best way, because if you chain into the old handler you never know how expensive thats going to be (how long it will take), and you dont want to miss your own interrupts or get your behind in frame generation.

you also dont need the whole counter_reset thing. just inc your ticks++ and trigger EOI. keep your timer as short as possible.

The issue is, I would like to use stable high-frequency IRQ to play Ad Lib music and MIDI while using SDL. Currently, if the BIOS handler cannot be called at the default frequency, the time stamps in the log will be incorrect. I am not sure what other side effects there might be in SDL.

Reply 5 of 7, by BloodyCactus

User metadata
Rank Oldbie
Rank
Oldbie

in that case you will have to approximate the calls. if you know your timer is 4x, then every 4th call, manually call the old handler and dont EOI (assume the old handler will EOI).

--/\-[ Stu : Bloody Cactus :: [ https://bloodycactus.com :: http://kråketær.com ]-/\--

Reply 6 of 7, by PalMusicFan

User metadata
Rank Newbie
Rank
Newbie
BloodyCactus wrote on Today, 13:28:

in that case you will have to approximate the calls. if you know your timer is 4x, then every 4th call, manually call the old handler and dont EOI (assume the old handler will EOI).

Thank you so much!
Reporting the result of my recent tests. Manually calling the old handler in my custom protect mode handler seems to work, but I cannot block the old handler call. It seems that even if I set a new real mode handler, the BIOS handler is still being automatically called.

This is a piece of the code:

      _go32_dpmi_get_protected_mode_interrupt_vector (8, &pm_old_handler);
pm_new_handler.pm_offset = (int) pm_new8h;
pm_new_handler.pm_selector = _go32_my_cs ();
_go32_dpmi_chain_protected_mode_interrupt_vector (8, &pm_new_handler);

_go32_dpmi_get_real_mode_interrupt_vector (8, &rm_old_handler);
rm_new_handler.pm_offset = (int) rm_new8h;
_go32_dpmi_allocate_real_mode_callback_iret (&rm_new_handler, &r1);
_go32_dpmi_set_real_mode_interrupt_vector (8, &rm_new_handler);

Reply 7 of 7, by BloodyCactus

User metadata
Rank Oldbie
Rank
Oldbie

yeah I just looked it up, its an absolute mess, and pretty much no guarantees. lots of, it will happen, it wont happen, it might happen. terrible.

I would create a realmode handler that is just IRET and nothing else. do everything you need in pmode, and if realmode fires, it just exits doing nothing. (its hard to tell, if it fires if you need to EOI the realmode version or not. ugh. what a mess.

When your program runs under a DPMI host, hardware interrupts are caught by the DPMI host and passed to protected mode first; only if unhandled, they are then reflected to real mode. Therefore, in DPMI mode you can get away with installing only a protected-mode handler. However, if the interrupts happen at a high frequency (say, more than 10 KHz), and if your program spends lots of time calling real-mode DOS/BIOS functions, then the overhead of the interrupt reflection from real to protected mode might be too painful, and you should consider installing a real-mode interrupt handler in addition to the protected-mode one. Such a real-mode handler will be called before the interrupt gets to the DPMI host, and handle the interrupt entirely in real mode, so it must be written in assembly and located in conventional memory (below the 1MB mark). If you need to hook an interrupt with both PM and RM handlers, you must hook the PM interrupt first, then the RM one (because hooking the PM interrupt modifies the RM one). Also, you should know that some DPMI hosts don't allow you to hook the RM interrupt (CWSDPMI does), and some call both handlers, no matter in what mode the interrupt arrived (CWSDPMI will only call one of them); the only way to be sure is to try

--/\-[ Stu : Bloody Cactus :: [ https://bloodycactus.com :: http://kråketær.com ]-/\--