Discussion:
What is the difference between the various interrupt routines?
(too old to reply)
Johann 'Myrkraverk' Oskarsson
2019-10-10 15:52:43 UTC
Permalink
Dear c.o.m.programmer,

OpenWatcom has several different interrupt routines, namely

int386
int386x
int86
int86x
intdos
intdosx
intr
intrf

and others. The C Library Reference doesn't include any hint on when I
should choose one function over another.

So far I've just used intr() because it's the first one I came across.
Is it any better to use int386() or int386x() in protected mode
applications?

If context matters, then for now I'm mostly interested in the int 33
mouse functions.

[Copied but not cross posted to the openwatcom newsgroup, because I'm
using different NNTP servers.]
--
Johann | email: invalid -> com | www.myrkraverk.com/blog/
I'm not from the Internet, I just work there. | twitter: @myrkraverk
T. Ment
2019-10-10 17:29:01 UTC
Permalink
Post by Johann 'Myrkraverk' Oskarsson
OpenWatcom has several different interrupt routines, namely
int386
int386x
int86
int86x
intdos
intdosx
intr
intrf
and others. The C Library Reference doesn't include any hint on when I
should choose one function over another.
Looks similar to Borland and Microsoft. They prevent trashing registers
used by your C code. The best to use depends on which registers you care
about. The x variants are when you care about segment registers. A quick
search says intr uses a REGPACK union instead of REGS. Seems to be about
BP vs. not BP.

It's hard to say which is best. Depends on your requirements. I think
Mateusz uses Watcom. Maybe he knows more.
Mateusz Viste
2019-10-10 18:41:40 UTC
Permalink
Post by Johann 'Myrkraverk' Oskarsson
OpenWatcom has several different interrupt routines, namely
int386
int386x
int86
int86x
intdos
intdosx
intr
intrf
and others. The C Library Reference doesn't include any hint on when
I should choose one function over another.
It simply depends what registers you want to interact with. If you need
to set/get segment registers, use the "x" functions. intdos() and
intdosx() are the same as int86()/int86x() but with the intno being
hardcoded to 0x21. The '386' functions are, obviously, to be used if
you want to set/get extended (32 bits) registers - EAX, EBP, etc.
Finally, intr() is similar to int86x(), but with a slightly different
API and registers struct (and it includes BP). intrf() is something I
never heard about.
Post by Johann 'Myrkraverk' Oskarsson
If context matters, then for now I'm mostly interested in the int 33
mouse functions.
Then you should read chapter 5.6 of the Watcom Programmer's guide,
p. 29, titled "How can I use the mouse interrupt (0x33) with DOS/4GW".
This document is freely available on the web.

Mateusz
Johann 'Myrkraverk' Oskarsson
2019-10-13 14:52:50 UTC
Permalink
Post by Mateusz Viste
Post by Johann 'Myrkraverk' Oskarsson
If context matters, then for now I'm mostly interested in the int 33
mouse functions.
Then you should read chapter 5.6 of the Watcom Programmer's guide,
p. 29, titled "How can I use the mouse interrupt (0x33) with DOS/4GW".
This document is freely available on the web.
Thank you. Though the method described here doesn't seem to be much
different than polling int 33/3 directly. Am I right that in order to
make use if this, I'll have to use an event buffer for the mouse? I
imagine a circular buffer would be nice.

I have yet to try this with CauseWay, but it seems at first glance the
code will work as-is.

Is there a tangible benefit from using an interrupt handler for the
mouse rather than a querying int33/3?
--
Johann | email: invalid -> com | www.myrkraverk.com/blog/
I'm not from the Internet, I just work there. | twitter: @myrkraverk
T. Ment
2019-10-13 16:18:58 UTC
Permalink
On Sun, 13 Oct 2019 22:52:50 +0800, Johann 'Myrkraverk' Oskarsson wrote:
.
Post by Johann 'Myrkraverk' Oskarsson
Post by Mateusz Viste
Then you should read chapter 5.6 of the Watcom Programmer's guide,
p. 29, titled "How can I use the mouse interrupt (0x33) with DOS/4GW".
Watcom 10.6 Programmer's Guide has the same example, but without the
memory locking code. It's not needed if VMM is disabled. VMM may be
provided by DOS/4GW in the absence of a DPMI host, or by a DPMI host if
present. DOS/4GW disables VMM if the DOS4GVM environment variable is
unset. With a DPMI host, it would depend on which one. For Causeway, I
don't know the details yet.
Post by Johann 'Myrkraverk' Oskarsson
Thank you. Though the method described here doesn't seem to be much
different than polling int 33/3 directly. Am I right that in order to
make use if this, I'll have to use an event buffer for the mouse?
The 10.6 example code (like the OW example) sets up a click handler and
busy loop polls a variable, testing for a click. Not very efficient, but
it's only an example. They do say the DOS extender manages the real mode
buffers required. I don't see where they use (or need) any buffer in the
example application code.
Post by Johann 'Myrkraverk' Oskarsson
Is there a tangible benefit from using an interrupt handler for the
mouse rather than a querying int33/3?
Not given the inefficiency of the example. But if you don't poll fast
enough, you will miss mouse events. So you're right about the need for
an interrupt handler event buffer, but that means writing better code
than the example.
Johann 'Myrkraverk' Oskarsson
2019-10-13 22:16:17 UTC
Permalink
Post by Mateusz Viste
Then you should read chapter 5.6 of the Watcom Programmer's guide,
p. 29, titled "How can I use the mouse interrupt (0x33) with DOS/4GW".
This document is freely available on the web.
This code has the following function. What I'd like to know is what
exactly are the results of the various Watcom specific keywords here?

For example, _loadds. The manual has this to say
Post by Mateusz Viste
__loadds
Open Watcom C/C++ supports the __loadds keyword to describe functions
that require specific loading of the DS register to establish
addressability to the function's data segment. This keyword is useful
in describing a function that will be placed in a Microsoft Windows
or > OS/2 1.x Dynamic Link Library (DLL). See also the description of the
Post by Mateusz Viste
"nd" and "zu" options.
But I don't understand what "specific loading of the DS register" means
in terms of code generation. What does it mean in this particular instance?

Why are we using the far keyword in the function signature?

The #pragma off( check stack ) is also a little bit confusing. Why
exactly are we not checking for stack overflow in the mouse handler? Is
it because it makes no sense in an interrupt handler?

Why is there __parm in the #pragma aux? In the manual it's always just
parm. I have surmised that the register list coincides with the
parameter list documented here:

http://www.ctyme.com/intr/rb-5968.htm


#pragma off( check_stack )
void _loadds far click_handler( int max, int mbx,
int mcx, int mdx,
int msi, int mdi )
{
#pragma aux click_handler __parm [EAX] [EBX] [ECX] \
[EDX] [ESI] [EDI]
cbd.mouse_event = 1;

cbd.mouse_code = (unsigned short)max;
cbd.mouse_bx = (unsigned short)mbx;
cbd.mouse_cx = (unsigned short)mcx;
cbd.mouse_dx = (unsigned short)mdx;
cbd.mouse_si = (signed short)msi;
cbd.mouse_di = (signed short)mdi;
if( cbd.mouse_code & 8 )
cbd.right_button = 1;
}

/* Dummy function so we can calculate size of
code to lock (cbc_end - click_handler).
*/
void cbc_end( void )
{
}
#pragma on( check_stack )
--
Johann | email: invalid -> com | www.myrkraverk.com/blog/
I'm not from the Internet, I just work there. | twitter: @myrkraverk
T. Ment
2019-10-14 00:28:16 UTC
Permalink
Post by Johann 'Myrkraverk' Oskarsson
The #pragma off( check stack ) is also a little bit confusing. Why
exactly are we not checking for stack overflow in the mouse handler? Is
it because it makes no sense in an interrupt handler?
The mouse handler is not truly an interrupt handler. It's a callout
(some say callback) the mouse driver (the true interrupt handler) makes
on your behalf, to advise you of the interrupt, so you can record the
event in your ring buffer.

Your mouse handler code effectively becomes an extension of the true
mouse driver interrupt handler, and thus you must obey the same rules
required of all interrupt handlers.

Stack checking works within an application, because your application
code can look at SS, SP, and stack size to see if you've gone too far.

But an external interrupt handler cannot determine stack size of the
code it interrupted. Stack checking code can only make things worse.

All an interrupt handler can do, is assume application programmers are
sensible and leave enough unused stack space for interrupt handlers to
run without crashing the system.

That's the way it is on x86.
T. Ment
2019-10-14 13:00:22 UTC
Permalink
Post by T. Ment
Your mouse handler code effectively becomes an extension of the true
mouse driver interrupt handler, and thus you must obey the same rules
required of all interrupt handlers.
Except one. You don't return with an IRET. He did a far call to you, so
you do the usual far return back to him.
Johann 'Myrkraverk' Oskarsson
2019-10-14 19:24:40 UTC
Permalink
Post by T. Ment
Post by T. Ment
Your mouse handler code effectively becomes an extension of the true
mouse driver interrupt handler, and thus you must obey the same rules
required of all interrupt handlers.
Except one. You don't return with an IRET. He did a far call to you, so
you do the usual far return back to him.
That explains the far keyword in the function definition.

void _loadds far click_handler( int max, int mbx, ...

Though I'm still trying to understand why exactly the _loadds keyword is
there.
--
Johann | email: invalid -> com | www.myrkraverk.com/blog/
I'm not from the Internet, I just work there. | twitter: @myrkraverk
T. Ment
2019-10-14 20:15:03 UTC
Permalink
Post by Johann 'Myrkraverk' Oskarsson
void _loadds far click_handler( int max, int mbx, ...
I'm still trying to understand why exactly the _loadds keyword is there.
When the mouse driver interrupt handler executes, his DS has a value
associated with his data. Since your variables do not reside in the same
data segment as his, something must be done to fix DS with the correct
value for you.

_loadds seems like a good guess for doing that. But that's just my fuzzy
logic. Works often, but not always.
Johann 'Myrkraverk' Oskarsson
2019-10-17 13:56:16 UTC
Permalink
Post by Mateusz Viste
Then you should read chapter 5.6 of the Watcom Programmer's guide,
p. 29, titled "How can I use the mouse interrupt (0x33) with DOS/4GW".
This document is freely available on the web.
Ok, so I made a simple ring buffer for mouse events. I do have some
questions about the code in the example by Watcom though. I've
understood everything but the return value of the lock function. Why is
cflag negated on return? My version with liberal comments, so I don't
have to look up in manuals, follows.

Also, is there a simple way for me to test failure of the lock command?
I like to test error handling code, and if possible I'd like to test the
error code in the ax register (not set by the current version) as listed
here:

http://www.ctyme.com/intr/rb-5802.htm#Table3143

At the very least, I can fake error returns by removing the ! operator
(understanding why it's there is the reason I'm writing these
questions), so generating errors with the interrupt itself is not
required to test error handling code, but I'd like to.

I used __int16 and __int32 because it makes more sense to me when
assuming bit widths of the operations. I left the void * as is.

/* part of file: mouse.c */

/* We make this function static because it's not meant to be used
* outside of thise file. We keep the prefix mouse_ though.
*/
static int mouse_lock_region( void *address, unsigned __int32 length )
{
/* This function assumes pointers are 32bit wide.
*/
union REGS registers = { 0 };
unsigned __int32 linear = (unsigned __int32) address;
/* Just like DOS/4GW, CauseWay has a flat memory model, so
* converting the address is trivial.
*/

/* See the Ralf Brown interrupt list for int 31/ax=0600 for the
* details of the following call.
*
* http://www.ctyme.com/intr/rb-5852.htm
*/

registers.w.ax = 0x0600; /* DPMI lock linear region */
registers.w.bx = (unsigned __int16) ( linear >> 16 ); /* side */
registers.w.cx = (unsigned __int16) ( linear & 0xffff ); /* comments*/
registers.w.si = (unsigned __int16) ( length >> 16 ); /* cleared*/
registers.w.di = (unsigned __int16) ( length & 0xffff ); /* */
int386( 0x31, &registers, &registers );

/* On success, cf is clear, cf is set on error. On error, ax has
* the error code according to DPMI 1.0, so maybe it's not
* guaranteed to be set on a DPMI 0.9 host?

/* return the success or failure of the operation */
return !registers.w.cflag; /* Why is there a negation here? */
}
--
Johann | email: invalid -> com | www.myrkraverk.com/blog/
I'm not from the Internet, I just work there. | twitter: @myrkraverk
T. Ment
2019-10-17 16:13:22 UTC
Permalink
Why is cflag negated on return?
Because the caller wants it that way.
if( (! lock_ region( &cbd, sizeof( cbd ) ))
In the DPMI call, the carry flag is clear for success (=0), or set for
failure (=1). But that's backwards from C logic. The example code writer
could have written
if( (lock_ region( &cbd, sizeof( cbd ) ))
without the (!), but that would be less natural for the human brain to
understand. So he twists the function instead of your brain.
is there a simple way for me to test failure of the lock command?
By looking at the negated carry flag, he's already doing that.
I'd like to test the error code in the ax register
Can't do it without a DPMI 1.0 host.

As Ralf says in his hardcopy book, only Qualitas offered a DPMI 1.0
host. Bob Smith (Qualitas) later released DPMIONE, a stand alone open
source version. I tried it, but it's slow when accessing the disk.

But it's open source, if you have the time you can fix it. Bob is still
around, but has no interest in his old code. You're on your own.

https://stackoverflow.com/users/2114971/bob-smith

Rod Pemberton
2019-10-11 01:18:17 UTC
Permalink
On Thu, 10 Oct 2019 23:52:43 +0800
Post by Johann 'Myrkraverk' Oskarsson
OpenWatcom has several different interrupt routines, namely
int386
int386x
int86
int86x
intdos
intdosx
intr
intrf
I've not used intdos, intdos or bdos for calling 0x21 directly.
I've used intr for calling simple interrupts, e.g., set text mode.
I'm not sure what intrf is. It's not listed for OW v1.3.
I use int86/int86x for 16-bit RM interrupts.
I use int386/int386x for 32-bit PM interrupts.
Of course, the x is for the extended versions with segments.
Post by Johann 'Myrkraverk' Oskarsson
different NNTP
Yes, you have to (or had to) connect to OW's server directly to post.


Rod Pemberton
--
The U.S. government can't allow a government employee to anonymously
attack the President of the U.S.
Loading...