// --------------------------- BASE.H ------------------------------
// For use with with WATCOM 9.5 + DOS4GW
// (C) Copyright 1993/4 by Jare & JCAB of Iguana-VangeliSTeam.

/*
 * Base definitions and expected things like SREGS, NULL, etc.
 */

#ifndef _BASE_H_
#define _BASE_H_

#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include "os.h"

typedef unsigned char  byte;
typedef unsigned short word;
typedef unsigned int  dword;
typedef   signed char  sbyte;
typedef   signed short sword;
typedef   signed int  sdword;

typedef unsigned char  uint8;
typedef   signed char  sint8;
typedef unsigned short uint16;
typedef   signed short sint16;
typedef unsigned int  uint32;
typedef   signed int  sint32;

typedef uint8 bool;

typedef signed   int   sint;
typedef unsigned int   uint;
typedef signed   long  slong;
typedef unsigned long  ulong;

typedef int error;

#ifdef TRUE
#undef TRUE
#undef FALSE
#endif

enum {
    TRUE  = 1,
    FALSE = 0
};

#ifndef NULL
#define NULL (0L)
#endif

#define PUBLIC  extern
#define PRIVATE static

#define PUBLICFUNC __stdcall    // Defines a library function.
#define PUBLICDATA __stdcall    // Defines a library variable.

//#define PUBLICFUNC
#define LOCALFUNC


#ifndef swap
#define swap(a,b) ((a)^=(b),(b)^=(a),(a)^=(b))
#endif

#define swap16(w) ((w) = ((w) >> 8) | ((w) << 8))


#define inb(a)    inp(a)
#define outb(a,b) outp(a,b)
#define inw(a)    inpw(a)
#define outw(a,b) outpw(a,b)

//#pragma intrinsic(inp,inpw,outp,outpw)

PUBLIC int    ArgC;
PUBLIC char **ArgV;

static void* cusmalloc(int iSize)
{
  int i;

  byte* p= malloc(iSize);
  for (i = 0 ; i < iSize ; i++)
  {
    p[i] = rand() & 255;
  }

  return p;
}
#define NEW(a)     ((void*)(((a)>0)?cusmalloc((a)):NULL))
#define DISPOSE(a) (((a)!=NULL)?(void)(free((a)),(a)=NULL):(void)0)

PUBLIC void BASE_Require(const char *cond, const char *file, int line);
PUBLIC void BASE_Abort(const char *str, ...);

PUBLIC int BASE_CheckArg(const char *parm);

static void Breakpoint()
{
  __asm int 3;
}
#ifndef NDEBUG
#define REQUIRE(a) (a)
#else
#define REQUIRE(a) (a)
//#define breakpoint()
#endif


#define SIZEARRAY(a) (sizeof(a)/sizeof(*(a)))

#define ADDPOINTER(p,d)    ((void*)(((byte*)(p)) + (d)))
#define ADDPOINTERT(p,t,d) ((t)(((byte*)(p)) + (d)))



extern  sint32 FP0Div(sint32 a, sint32 b);
#define FP0Div(a,b) ((a)/(b))
extern  sint32 FP0Mult(sint32 a, sint32 b);
#define FP0Mult(a,b) ((a)*(b))

extern sint32 FP8Div(sint32 a, sint32 b);
/*//#pragma aux   FP8Div modify nomemory [EDX] parm [EAX] [ECX] value [EAX] = \
                    "MOV    EDX,EAX" \
                    "SAR    EDX,31"  \
                    "SHLD EDX,EAX,8" \
                    "SHL  EAX,8"     \
                    "IDIV ECX"*/
static sint32 FP8Mult(sint32 a, sint32 b)
{
///*//#pragma aux   FP8Mult modify nomemory parm [EAX] [EDX] value [EAX] =
  int ireturn;
  __asm
  {
    MOV eax, a
    MOV edx, b
    IMUL EDX        
    SHRD EAX,EDX,8
    mov ireturn, eax
  }

  return ireturn;
}

static sint32 FP16Div(sint32 a, sint32 b)
{
  assert(!"TEST");

  __asm
  {
    mov    eax, a
    mov    ecx, b
    MOV    EDX,EAX
    SAR    EDX,31
    SHLD EDX,EAX,16
    SHL  EAX,16
    IDIV ECX
    ret
  }
}
/*//#pragma aux   FP16Div modify nomemory [EDX] parm [EAX] [ECX] value [EAX] = \
                    "MOV    EDX,EAX" \
                    "SAR    EDX,31"  \
                    "SHLD EDX,EAX,16" \
                    "SHL  EAX,16"     \
                    "IDIV ECX"*/

static sint32 FP16Mult(sint32 a, sint32 b)
{
  __asm
  {
    mov eax, a
    mov edx, b
    imul edx
    shrd eax, edx, 16
    ret
  }
}
/*//#pragma aux   FP16Mult modify nomemory parm [EAX] [EDX] value [EAX] = \
                    "IMUL EDX"        \
                    "SHRD EAX,EDX,16"*/

extern sint32 FP24Div(sint32 a, sint32 b);
/*//#pragma aux   FP24Div modify nomemory [EDX] parm [EAX] [ECX] value [EAX] = \
                    "MOV    EDX,EAX" \
                    "SAR    EDX,31"  \
                    "SHLD EDX,EAX,24" \
                    "SHL  EAX,24"     \
                    "IDIV ECX"*/

extern sint32 FP24Mult(sint32 a, sint32 b);
/*//#pragma aux   FP24Mult modify nomemory parm [EAX] [EDX] value [EAX] = \
                    "IMUL EDX"        \
                    "SHRD EAX,EDX,24"*/

extern sint32 FP32Div(sint32 a, sint32 b);
/*//#pragma aux   FP32Div modify nomemory [EAX] parm [EDX] [ECX] value [EAX] = \
                    "XOR  EAX,EAX"    \
                    "IDIV ECX"*/

extern sint32 FP32Mult(sint32 a, sint32 b);
/*//#pragma aux   FP32Mult modify nomemory parm [EAX] [EDX] value [EDX] = \
                    "IMUL EDX"*/

static sint32 FPnDiv(sint32 a, sint32 b, uint32 r)
{
    assert(!"TEST");
    __asm 
    {
        mov eax, a;
        mov ebx, b;
        mov ecx, r;

        mov edx, eax;
        sar edx, 31
        shld edx, eax, cl;
        shl eax, cl;
        idiv ebx;
        ret
    }
}
/*//#pragma aux   FPnDiv modify nomemory [EDX] parm [EAX] [EBX] [ECX] value [EAX] = \
                    "MOV    EDX,EAX" \
                    "SAR    EDX,31"  \
                    "SHLD EDX,EAX,CL" \
                    "SHL  EAX,CL"     \
                    "IDIV EBX"
*/
extern sint32 FP16Pow2(sint32 a);
/*//#pragma aux   FP16Pow2 modify nomemory [EDX] parm [EAX] value [EAX] = \
                    "IMUL EAX"        \
                    "SHRD EAX,EDX,16"
                    */

extern sint32 FP24Pow2(sint32 a);
/*//#pragma aux   FP24Pow2 modify nomemory [EDX] parm [EAX] value [EAX] = \
                    "IMUL EAX"        \
                    "SHRD EAX,EDX,24"*/

extern sint32 FP32Pow2(sint32 a);
/*//#pragma aux   FP32Pow2 modify nomemory parm [EAX] value [EDX] = \
                    "IMUL EAX"*/


extern sint32 FPnMult(sint32 a, sint32 b, uint32 r);
/*//#pragma aux   FPnMult modify nomemory parm [EAX] [EDX] [ECX] value [EAX] = \
                    "IMUL EDX"        \
                    "SHRD EAX,EDX,CL"
*/
static sint32 FPMultDiv(sint32 a, sint32 b, sint32 c)
{
    assert(!"TEST");
    __asm
    {
        mov eax, a;
        mov edx, b;
        mov ebx, c;
        imul edx;
        idiv ebx;
        ret
    }
}
/*//#pragma aux   FPMultDiv modify nomemory parm [EAX] [EDX] [EBX] value [EAX] = \
                    "IMUL EDX"        \
                    "IDIV EBX"
*/
extern sint32 FPUMultDiv(sint32 a, sint32 b, sint32 c);
/*//#pragma aux   FPUMultDiv modify nomemory parm [EAX] [EDX] [EBX] value [EAX] = \
                    "MUL EDX"        \
                    "DIV EBX"
*/
static uint32 FP16Inverse(uint32 a)     // 1/a  all 16.16
{
    assert(!"TEST");
    __asm
    {
        mov ecx, a;
        xor eax, eax;
        mov edx, 1;
        div ecx;
        ret;
    }
}
/*//#pragma aux FP16Inverse modify nomemory [EDX] parm [ECX] value [EAX] = \
        "XOR    EAX,EAX"    \
        "MOV    EDX,1"      \
        "DIV    ECX"
        */

extern void RepStosd(void *d, dword c, uint32 a);
/*//#pragma aux RepStosd parm [EDI] [EAX] [ECX] = \
        "CLD" \
        "REP STOSD"
*/
static void MemSetD(void *d, uint32 a, dword c)
{
    dword  i;
    dword* pu = (dword*) d;

    if (c & 3) assert(!"NYI");
    c>>=2;
    for (i = 0 ; i < c ; i++)
    {
        pu[i] = a;
    }

    /*
    __asm
    {
        mov ecx, c
        shr ecx, 2
        mov edi, d
        mov 
    }*/
}
/*//#pragma aux MemSetD parm [EDI] [EAX] [ECX] = \
        "PUSH ECX"   \
        "SHR  ECX,2" \
        "REP STOSD"  \
        "POP  ECX"   \
        "AND  ECX,3" \
        "REP STOSB"
*/
extern void MemSetW(void *d, dword c, uint32 a);
/*//#pragma aux MemSetW parm [EDI] [EAX] [ECX] = \
        "SHR ECX,1"     \
        "REP STOSW"     \
        "ADC ECX,ECX"   \
        "REP STOSB"
*/
extern void MemSetB(void *d, dword c, uint32 a);
/*//#pragma aux MemSetB parm [EDI] [EAX] [ECX] = \
        "REP STOSB"
        */

extern void RepMovsb(void *d, const void *c, uint32 a);
/*//#pragma aux RepMovsb parm [EDI] [ESI] [ECX] = \
        "CLD"        \
        "PUSH ECX"   \
        "SHR  ECX,2" \
        "REP MOVSD"  \
        "POP  ECX"   \
        "AND  ECX,3" \
        "REP MOVSB"
        */

extern void RepMovsd(void *d, const void *c, uint32 a);
/*//#pragma aux RepMovsd parm [EDI] [ESI] [ECX] = \
        "CLD"        \
        "REP MOVSD"
*/
// ---------------------- Returns (a>0 ? 1 : -1) ------------------------
sint32 Sgn(sint32 a);
/*
//#pragma aux Sgn modify nomemory          \
        parm caller [EAX]                \
        value [EAX] =                    \
        "SAR EAX,31"                     \
        "SHL EAX,1"                      \
        "INC EAX"
        */

// ---------------------- Returns (a>0 ? a : -a) ------------------------
static sint32 Abs32(sint32 a)
{
    int ireturn;
    __asm
    {
        mov ebx, a;
        MOV EAX,EBX
        ADD EBX,EBX
        SBB EBX,EBX
        XOR EAX,EBX
        SUB EAX,EBX
        mov ireturn, eax
    }

    return ireturn;
}
/*//#pragma aux Abs32 modify nomemory        \
        parm caller [EBX]                \
        value [EAX] =                    \
        "MOV EAX,EBX"                    \
        "ADD EBX,EBX"                    \
        "SBB EBX,EBX"                    \
        "XOR EAX,EBX"                    \
        "SUB EAX,EBX"
*/
// ---------------------- Returns a^2
static sint32 Pow2(sint32 a)
{
    assert(!"TEST");
    __asm
    {
        mov eax, a;
        imul eax;
        ret;
    }
}
/*//#pragma aux Pow2 modify nomemory         \
        parm caller [EDX]                \
        value [EAX] =                    \
        "MOV EAX,EDX"                    \
        "IMUL EAX"
*/
sint32 Pow3(sint32 a);
/*//#pragma aux Pow3 modify nomemory         \
        parm caller [EDX]                \
        value [EAX] =                    \
        "MOV EAX,EDX"                    \
        "IMUL EAX,EAX"                   \
        "IMUL EDX"
*/
// ---------------------- Endian stuff

static dword BSwapDword(dword a)
{
  __asm
  {
    mov eax, a
    XCHG   AL,AH
    ROR    EAX,16
    XCHG   AL,AH
  }
}
/*//#pragma aux  BSwapDword modify nomemory parm [EAX] value [EAX] = \
    "XCHG   AL,AH"  \
    "ROR    EAX,16" \
    "XCHG   AL,AH"
*/
static dword BSwapWord(dword a)
{
  __asm
  {
  mov eax, a
  xchg al, ah
  ret
  }
}
/*//#pragma aux  BSwapWord modify nomemory parm [EAX] value [EAX] = \
    "XCHG   AL,AH"
*/
// ---------------------- Get Segment values

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

extern void FinishProgram(void);

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

PUBLIC dword RND_Seed1, RND_Seed2, RND_Seed3;

#define BIOS_Clock (((dword *)0x46C)[0])

PUBLIC void RND_Randomize(dword seed);
/*//#pragma aux RND_Randomize parm [EAX] = \
    "    MOV     [RND_Seed1],EAX"  \
    "    ROR     EAX,13         "  \
    "    MOV     [RND_Seed2],EAX"  \
    "    ROR     EAX,9          "  \
    "    MOV     [RND_Seed3],EAX"
    */

static dword RND_GetNum(void)
{
  int ireturn;
  /*
  int eax = RND_Seed1;
  int ebx = RND_Seed2;
  int edx = RND_Seed3;
  eax+= 0x0B35FA137;
  ebx+= 0x0354C63f7;
  edx+= 0x0067B784B;
  */
    __asm
    {
      MOV     EAX,[RND_Seed1]
      MOV     EBX,[RND_Seed2]
      MOV     EDX,[RND_Seed3]
      ADD     EAX,0x0B35FA137
      ADD     EBX,0x0354C63f7
      ADD     EDX,0x0067B784B
      ROL     EAX,2          
      MOV     [RND_Seed1],EAX
      ADD     EBX,EAX        
      ROR     EBX,1          
      MOV     [RND_Seed2],EBX
      SUB     EDX,EBX        
      XOR     EAX,EDX        
      MOV     [RND_Seed3],EDX
      ADD     EAX,EBX        
      MOV     ireturn, EAX;
    }

    return ireturn;
}
/*//#pragma aux RND_GetNum modify nomemory [EBX EDX] value [EAX] = \
    "    MOV     EAX,[RND_Seed1]" \
    "    MOV     EBX,[RND_Seed2]" \
    "    MOV     EDX,[RND_Seed3]" \
    "    ADD     EAX,0x0B35FA137" \
    "    ADD     EBX,0x0354C63f7" \
    "    ADD     EDX,0x0067B784B" \
    "    ROL     EAX,2          " \
    "    MOV     [RND_Seed1],EAX" \
    "    ADD     EBX,EAX        " \
    "    ROR     EBX,1          " \
    "    MOV     [RND_Seed2],EBX" \
    "    SUB     EDX,EBX        " \
    "    XOR     EAX,EDX        " \
    "    MOV     [RND_Seed3],EDX" \
    "    ADD     EAX,EBX        "
    */
#endif

// --------------------------- BASE.H ------------------------------
