//  This may look like C code, but it is really -*- C++ -*-

//  ------------------------------------------------------------------
//  The Goldware Library
//  Copyright (C) 1990-1999 Odinn Sorensen
//  Copyright (C) 1999-2000 Alexander S. Aganichev
//  ------------------------------------------------------------------
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Library General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Library General Public License for more details.
//
//  You should have received a copy of the GNU Library General Public
//  License along with this program; if not, write to the Free
//  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
//  MA 02111-1307, USA
//  ------------------------------------------------------------------
//  $Id$
//  ------------------------------------------------------------------
//  Intel 80x86 interrupt portable wrapper class.
//  ------------------------------------------------------------------

#ifndef __gmemi86_h
#define __gmemi86_h


//  ------------------------------------------------------------------

#if defined(__MSDOS__)


//  ------------------------------------------------------------------

#include <dos.h>
#include <gdefs.h>


//  ------------------------------------------------------------------

#if defined(__WATCOMC__)

    #define GREGPACK REGPACK

#elif defined(__DJGPP__)

    #include <dpmi.h>
    #define GREGPACK __dpmi_regs

#elif defined(__BORLANDC__)

    #define GREGPACK REGS

#else

    #error not supported!

#endif


//  ------------------------------------------------------------------

class i86
{

protected:

    GREGPACK r;
#if defined(__BORLANDC__)
    SREGS sr;
#endif

public:

    inline uint al()
    {
        return r.h.al;
    }
    inline uint ah()
    {
        return r.h.ah;
    }
    inline uint bl()
    {
        return r.h.bl;
    }
    inline uint bh()
    {
        return r.h.bh;
    }
    inline uint cl()
    {
        return r.h.cl;
    }
    inline uint ch()
    {
        return r.h.ch;
    }
    inline uint dl()
    {
        return r.h.dl;
    }
    inline uint dh()
    {
        return r.h.dh;
    }
#ifdef __DJGPP__
    inline uint ax()
    {
        return r.x.ax;
    }
    inline uint bx()
    {
        return r.x.bx;
    }
    inline uint cx()
    {
        return r.x.cx;
    }
    inline uint dx()
    {
        return r.x.dx;
    }
    inline uint bp()
    {
        return r.x.bp;
    }
    inline uint si()
    {
        return r.x.si;
    }
    inline uint di()
    {
        return r.x.di;
    }
    inline uint ds()
    {
        return r.x.ds;
    }
    inline uint es()
    {
        return r.x.es;
    }
    inline uint flags()
    {
        return r.x.flags;
    }
#else
    inline uint ax()
    {
        return r.w.ax;
    }
    inline uint bx()
    {
        return r.w.bx;
    }
    inline uint cx()
    {
        return r.w.cx;
    }
    inline uint dx()
    {
        return r.w.dx;
    }
    inline uint bp()
    {
        return r.w.bp;
    }
    inline uint si()
    {
        return r.w.si;
    }
    inline uint di()
    {
        return r.w.di;
    }
#if defined(__BORLANDC__)
    inline uint ds()
    {
        return sr.w.ds;
    }
    inline uint es()
    {
        return sr.w.es;
    }
#else
    inline uint ds()
    {
        return r.w.ds;
    }
    inline uint es()
    {
        return r.w.es;
    }
#endif
    inline uint flags()
    {
        return r.w.flags;
    }
#endif

    inline void al(uint32_t b)
    {
        r.h.al = (byte)b;
    }
    inline void ah(uint32_t b)
    {
        r.h.ah = (byte)b;
    }
    inline void bl(uint32_t b)
    {
        r.h.bl = (byte)b;
    }
    inline void bh(uint32_t b)
    {
        r.h.bh = (byte)b;
    }
    inline void cl(uint32_t b)
    {
        r.h.cl = (byte)b;
    }
    inline void ch(uint32_t b)
    {
        r.h.ch = (byte)b;
    }
    inline void dl(uint32_t b)
    {
        r.h.dl = (byte)b;
    }
    inline void dh(uint32_t b)
    {
        r.h.dh = (byte)b;
    }
#ifdef __DJGPP__
    inline void ax(uint32_t w)
    {
        r.x.ax = (word)w;
    }
    inline void bx(uint32_t w)
    {
        r.x.bx = (word)w;
    }
    inline void cx(uint32_t w)
    {
        r.x.cx = (word)w;
    }
    inline void dx(uint32_t w)
    {
        r.x.dx = (word)w;
    }
    inline void bp(uint32_t w)
    {
        r.x.bp = (word)w;
    }
    inline void si(uint32_t w)
    {
        r.x.si = (word)w;
    }
    inline void di(uint32_t w)
    {
        r.x.di = (word)w;
    }
    inline void ds(uint32_t w)
    {
        r.x.ds = (word)w;
    }
    inline void es(uint32_t w)
    {
        r.x.es = (word)w;
    }
    inline void flags(uint32_t w)
    {
        r.x.flags = (word)w;
    }
#else
    inline void ax(uint32_t w)
    {
        r.w.ax = (word)w;
    }
    inline void bx(uint32_t w)
    {
        r.w.bx = (word)w;
    }
    inline void cx(uint32_t w)
    {
        r.w.cx = (word)w;
    }
    inline void dx(uint32_t w)
    {
        r.w.dx = (word)w;
    }
    inline void bp(uint32_t w)
    {
        r.w.bp = (word)w;
    }
    inline void si(uint32_t w)
    {
        r.w.si = (word)w;
    }
    inline void di(uint32_t w)
    {
        r.w.di = (word)w;
    }
#if defined(__BORLANDC__)
    inline void ds(uint32_t w)
    {
        sr.w.ds = (word)w;
    }
    inline void es(uint32_t w)
    {
        sr.w.es = (word)w;
    }
#else
    inline void ds(uint32_t w)
    {
        r.w.ds = (word)w;
    }
    inline void es(uint32_t w)
    {
        r.w.es = (word)w;
    }
#endif
    inline void flags(uint32_t w)
    {
        r.w.flags = (word)w;
    }
#endif

    void genint(int intno);
};


//  ------------------------------------------------------------------
//  Inline implementations

inline void i86::genint(int intno)
{

#if defined(__BORLANDC__)
#if defined(__DPMI32__)
    int386x(intno, &r, &r, &sr);
#else
    int86x(intno, &r, &r, &sr);
#endif
#elif defined(__DJGPP__)
    __dpmi_int(intno, &r);
#else
    intr(intno, &r);
#endif
}


#if defined(__WATCOMC__) && defined(__386__)
inline int __dpmi_allocate_dos_memory(long len, int &buf)
{

    i86 cpu;
    // Determine how much is available
    cpu.ax(0x100);
    cpu.bx(65535u);
    cpu.genint(0x31);
    if(len > (long)cpu.bx()*16L)
        return -1;
    cpu.ax(0x100);
    cpu.bx(len);
    cpu.genint(0x31);
    *buffer = (int) cpu.dx();
    return (int) cpu.ax();
}


inline void __dpmi_free_dos_memory(int buffer)
{

    i86 cpu;
    cpu.ax(0x101);
    cpu.dx((word) buffer);
    cpu.genint(0x31);
}
#endif


//  ------------------------------------------------------------------
//  A more portable version of MK_FP()

#if defined(__WATCOMC__) && defined(__386__)

#define gmkfp(s,o) ((s << 4) + o)

#elif defined(__DJGPP__)

#include <sys/nearptr.h>
#include <crt0.h>

inline void *gmkfp(uint16_t seg, uint16_t ofs)
{
    if(not (_crt0_startup_flags & _CRT0_FLAG_NEARPTR))
        if(not __djgpp_nearptr_enable())
            return (void *)0;
    return (void *)(seg*16 + ofs + __djgpp_conventional_base);
}

#else

#define gmkfp(s,o) MK_FP(s,o)

#endif


//  ------------------------------------------------------------------

#endif
#endif

//  ------------------------------------------------------------------
