⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pgdos32q.gml

📁 开放源码的编译器open watcom 1.6.0版的源代码
💻 GML
📖 第 1 页 / 共 4 页
字号:
    This can be done with DPMI call 100h.  This program
    will call DOS int 21, function 39h, "Create
    Directory".

    Compile & Link: wcl386 -l=dos4g simulate
*/
#include <i86.h>
#include <dos.h>
#include <stdio.h>
#include <string.h>

.code break
static struct rminfo {
    long EDI;
    long ESI;
    long EBP;
    long reserved_by_system;
    long EBX;
    long EDX;
    long ECX;
    long EAX;
    short flags;
    short ES,DS,FS,GS,IP,CS,SP,SS;
} RMI;
.code break

void main()
{
    union REGS regs;
    struct SREGS sregs;
    int interrupt_no=0x31;
    short selector;
    short segment;
    char far *str;

    /* DPMI call 100h allocates DOS memory */
    memset(&sregs,0,sizeof(sregs));
    regs.w.ax=0x0100;
    regs.w.bx=0x0001;
    int386x( interrupt_no, &regs, &regs, &sregs);
    segment=regs.w.ax;
    selector=regs.w.dx;
.code break

    /* Move string to DOS real-mode memory */
    str=MK_FP(selector,0);
    _fstrcpy( str, "myjunk" );

    /* Set up real-mode call structure */
    memset(&RMI,0,sizeof(RMI));
    RMI.EAX=0x00003900; /* call service 39h ah=0x39  */
    RMI.DS=segment;     /* put DOS seg:off into DS:DX*/
    RMI.EDX=0;          /* DOS ignores EDX high word */
.code break

    /* Use DPMI call 300h to issue the DOS interrupt */
    regs.w.ax = 0x0300;
    regs.h.bl = 0x21;
    regs.h.bh = 0;
    regs.w.cx = 0;
    sregs.es = FP_SEG(&RMI);
    regs.x.edi = FP_OFF(&RMI);
    int386x( interrupt_no, &regs, &regs, &sregs );
}
.code end
.*
.section How do you install a bi-modal interrupt handler using DOS/4GW?
.*
.np
.ix 'DOS/4GW' 'bi-modal interrupt'
.ix 'bi-modal interrupt'
Due to the nature of the protected-mode/real-mode interface, it is often
difficult to handle high speed communications with hardware interrupt
handlers.
For example, if you install your communications interrupt handler in
protected mode, you may find that some data is lost when transmitting
data from a remote machine at the rate of 9600 baud.
This occurs because the data arrived at the communication port while the
machine was in the process of transferring the previous interrupt up to
protected mode.
Data will also be lost if you install the interrupt handler in real mode
since your program, running in protected mode, will have to switch down
into real mode to handle the interrupt.
The reason for this is that the data arrived at the communication port
while the DOS extender was switching between real mode and protected
mode, and the machine was not available to process the interrupt.
.np
To avoid the delay caused by switching between real-mode and protected
mode to handle hardware interrupts, install interrupt handlers in both
real-mode and protected-mode.
During the execution of a protected-mode program, the system often
switches down into real-mode for DOS system calls.
If a communications interrupt occurs while the machine is in real-mode,
then the real-mode interrupt handler will be used.
If the interrupt occurs when the machine is executing in protected-mode,
then the protected-mode interrupt handler will be used.
This enables the machine to process the hardware interrupts faster and
avoid the loss of data caused by context switching.
.np
Installing the interrupt handlers in both protected-mode and real-mode
is called bi-modal interrupt handling.
The following program is an example of how to install both handlers for
Interrupt 0x0C (also known as COM1 or IRQ4).
The program writes either a 'P' to absolute address 0xB8002 or an 'R' to
absolute address 0xB8000.
These locations are the first two character positions in screen memory
for a color display.
As the program runs, you can determine which interrupt is handling the
COM1 port by the letter that is displayed.
A mouse attached to COM1 makes a suitable demo.
Type on the keyboard as you move the mouse around.
The ESC key can be used to terminate the program.
Transmitted data from a remote machine at 9600 baud can also be used to
test the COM1 handling.
.code begin
/*
    BIMODAL.C - The following program demonstrates how
    to set up a bi-modal interrupt handler for DOS/4GW

    Compile and link: wcl386 -l=dos4g bimodal bimo.obj
*/

#include <stdio.h>
#include <conio.h>
#include <dos.h>

#define D32RealSeg(P)   ((((DWORD) (P)) >> 4) & 0xFFFF)
#define D32RealOff(P)   (((DWORD) (P)) & 0xF)

typedef unsigned int WORD;
typedef unsigned long DWORD;

extern void com1_init (void);
extern void __interrupt pmhandler (void);
extern void __interrupt __far rmhandler (void);
.code break

void *D32DosMemAlloc (DWORD size)
{
    union REGS r;

    r.x.eax = 0x0100;           /* DPMI allocate DOS memory */
    r.x.ebx = (size + 15) >> 4; /* Number of paragraphs requested */
    int386 (0x31, &r, &r);

    if( r.x.cflag )  /* Failed */
        return ((DWORD) 0);
    return (void *) ((r.x.eax & 0xFFFF) << 4);
}
.code break

void main (void)
{
    union REGS      r;
    struct SREGS    sr;
    void           *lowp;
    void far       *fh;
    WORD            orig_pm_sel;
    DWORD           orig_pm_off;
    WORD            orig_rm_seg;
    WORD            orig_rm_off;
    int             c;

/*  Save the starting protected-mode handler address */
    r.x.eax = 0x350C;   /* DOS get vector (INT 0Ch) */
    sr.ds = sr.es = 0;
    int386x (0x21, &r, &r, &sr);
    orig_pm_sel = (WORD) sr.es;
    orig_pm_off = r.x.ebx;
.code break

/*
    Save the starting real-mode handler address using DPMI
    (INT 31h).
*/
    r.x.eax = 0x0200;   /* DPMI get real mode vector */
    r.h.bl = 0x0C;
    int386 (0x31, &r, &r);
    orig_rm_seg = (WORD) r.x.ecx;
    orig_rm_off = (WORD) r.x.edx;
.code break

/*
    Allocate 128 bytes of DOS memory for the real-mode
    handler, which must of course be less than 128 bytes
    long.  Then copy the real-mode handler into that
    segment.
*/
    if(! ( lowp = D32DosMemAlloc(128) ) ) {
        printf ("Couldn't get low memory!\n");
        exit (1);
    }
    memcpy (lowp, (void *) rmhandler, 128);
.code break

/*
    Install the new protected-mode vector.  Because INT 0Ch
    is in the auto-passup range, its normal "passdown"
    behavior will change as soon as we install a
    protected-mode handler.  After this next call, when a
    real mode INT 0Ch is generated, it will be resignalled
    in protected mode and handled by pmhandler.
*/
    r.x.eax = 0x250C;   /* DOS set vector (INT 0Ch) */
    fh = (void far *) pmhandler;
    r.x.edx = FP_OFF (fh);
    /* DS:EDX == &handler */
    sr.ds = FP_SEG (fh);
    sr.es = 0;
    int386x (0x21, &r, &r, &sr);
.code break

/*
    Install the new real-mode vector.  We do this after
    installing the protected-mode vector in order to
    override the "passup" behavior.  After the next call,
    interrupts will be directed to the appropriate handler,
    regardless of which mode we are in when they are
    generated.
*/
    r.x.eax = 0x0201;
    r.h.bl = 0x0C;
    /* CX:DX == real mode &handler */
    r.x.ecx = D32RealSeg(lowp);
    r.x.edx = D32RealOff(lowp);
    int386 (0x31, &r, &r);
.code break

/*
    Initialize COM1.
*/
    com1_init ();

    puts( "Move mouse, transmit data; ESC to quit\n" );

    while( 1 ) {
        if( kbhit() ) {
            if( ( (c = getch ()) & 0xff ) == 27 )
                    break;
            putch (c);
        }
    delay( 1 );
    }
.code break

/*
    Clean up.
*/
    r.x.eax = 0x250C;   /* DOS set vector (INT 0Ch) */
    r.x.edx = orig_pm_off;
    sr.ds = orig_pm_sel;    /* DS:EDX == &handler */
    sr.es = 0;
    int386x (0x21, &r, &r, &sr);

    r.x.eax = 0x0201;   /* DPMI set real mode vector */
    r.h.bl = 0x0C;
    /* CX:DX == real mode &handler */
    r.x.ecx = (DWORD) orig_rm_seg;
    r.x.edx = (DWORD) orig_rm_off;
    int386 (0x31, &r, &r);
}
.code end
.np
You will also need to create the following assembler code module.
The first part provides the interrupt handling routine for the
real-mode interrupt handler.
The second provides the protected-mode version of the interrupt
handler.
.code begin
;**
;** bimo.asm:
;** Assembler code for real-mode and protected-mode
;** INT 0xC interrupt handlers to support the INT 0xC
;** interrupt in both modes
;**
.li .386
;**
;** The real-mode interrupt handler is in a 16-bit code
;** segment so that the assembler will generate the right
;** code.  We will copy this code down to a 16-bit segment
;** in low memory rather than executing it in place.
;**

_TEXT16 SEGMENT BYTE PUBLIC USE16 'CODE'
    ASSUME  cs:_TEXT16

    PUBLIC  rmhandler_
rmhandler_:
    push    es
    push    bx
    mov     bx,0B800h
    mov     es,bx                   ; ES = 0xB800
    sub     bx,bx                   ; BX = 0
    mov     WORD PTR es:[bx],0720h  ; Clear 2 char cells
    mov     WORD PTR es:[bx+2],0720h
    mov     BYTE PTR es:[bx],'R'    ; Write R to memory
    pop     bx
    pop     es
    push    ax
    push    dx
    mov     dx,03FAh
    in      al,dx                   ; Read ports so
    mov     dx,03F8h                ; interrupts can
    in      al,dx                   ; continue to be
    mov     dx,020h                 ; generated
    mov     al,dl
    out     dx,al                   ; Send EOI
    pop     dx
    pop     ax
    iret
_TEXT16 ENDS
.code break
;**
;** The protected-mode interrupt handler is in a 32-bit code
;** segment.  Even so, we have to be sure to force an IRETD
;** at the end of the handler, because MASM doesn't generate
;** one.  This handler will be called on a 32-bit stack by
;** DOS/4GW.
;**
;** _DATA is the flat model data segment, which we load into
;** ES so we can write to absolute address 0xB8000.  (In the
;** flat model, DS is based at 0.)
;**
_DATA   SEGMENT BYTE PUBLIC USE32 'DATA'
_DATA   ENDS
.code break

DGROUP GROUP _DATA

_TEXT   SEGMENT BYTE PUBLIC USE32 'CODE'
    ASSUME  cs:_TEXT

    PUBLIC  com1_init_
com1_init_:
    mov     ax,0F3h                 ; 9600,n,8,1
    mov     dx,0                    ; com1
    int     14h                     ; Initialize COM1
    mov     bx,03F8h                ; COM1 port space
    lea     dx,[bx+5]               ; line status reg
    in      al,dx
    lea     dx,[bx+4]               ; modem control reg
    in      al,dx
    or      al,8                    ; enable OUT2 int
    out     dx,al
    lea     dx,[bx+2]               ; int id register
    in      al,dx
    mov     dx,bx                   ; data receive reg
    in      al,dx
    in      al,21h                  ; interrupt mask reg
    and     al,0EFh                 ; force IRQ4 unmask
    out     21h,al
    lea     dx,[bx+1]               ; int enable reg
    mov     al,1
    out     dx,al                   ; enable received int
    ret
.code break

    PUBLIC  pmhandler_
pmhandler_:
    push    es
    push    bx
    mov     bx,DGROUP
    mov     es,bx
    mov     ebx,0B8000h             ; ES:EBX=flat:0B8000h
    mov     DWORD PTR es:[ebx],07200720h  ; Clear cells
    mov     BYTE PTR es:[ebx+2],'P' ; Write P to memory
    pop     bx
    pop     es
    push    ax
    push    dx
    mov     dx,03FAh
    in      al,dx                   ; Read ports so
    mov     dx,03F8h                ; interrupts can
    in      al,dx                   ; continue to be
    mov     dx,020h                 ; generated
    mov     al,dl
    out     dx,al                   ; Send EOI
    pop     dx
    pop     ax
    iretd
_TEXT   ENDS
    END
.code end
.*
.do end

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -