/*

realmem.c - Test real mode memory functions

*/

#include <stdio.h>
#define APIENTRY __stdcall
#include <tntapi.h>

#define TRUE 1

#define RP_OFF(rp) ((WORD)(((DWORD)(rp)) & 0xFFFF))
#define RP_SEG(rp) ((WORD)(((DWORD)(rp)) >> 16))
#define RP_SET(rp, off, seg) (rp = ((DWORD)(seg) << 16) + (off))

int APIENTRY GetLastError();

main()

{

	static char test_str[] = "Testing 1 2 3......";

	extern void hello16(), reg_test16(), stack_test16(), pascal_test16();

	char buff[512];
	WORD dosmem;
	DWORD mysize;
	DWORD myflags;
	REALPTR realptr;
	WORD pcount;
	DWORD rc;
	DWORD erc;
	REGS16 regs;
	DWORD stackp;
	WORD *sizep;

	/* Print out a hello world message */

	printf("Test program for TNT real mode memory functions\n\n");

	/* Test GetDOSMemSelector */

	printf("GetDOSMemSelector test.\n");
	dosmem = GetDOSMemSelector();
	printf("Selector pointing to DOS memory = <<%04X>>\n", dosmem);
	if(dosmem == 0)
	{
		printf("GetDOSMemSelector failed.\n");
	}
	else
	{
		_asm sub eax,eax
		_asm mov ax,dosmem
		_asm lsl eax,eax
		_asm mov mysize,eax
		_asm pushfd
		_asm pop myflags
		++mysize;
		if(myflags & 0x40)
		{
			printf("Segment size = <<%08lX>>\n", mysize);
			if(mysize != 0x100000 && mysize != 0x110000)
				printf("Error -- invalid segment size.\n");
		}
		else
		{
			printf("Error -- invalid selector.\n");
		}

	}
	printf("\n");

	/* Test allocating and freeing real mode memory */

	printf("RealAlloc and RealFree test.\n");
	pcount = 16;
	realptr = RealAlloc(pcount);
	if(realptr == 0)
	{
		printf("RealAlloc failed -- error code %d.\n",
		       GetLastError());
		goto alloc_skip;
	}
	printf("Allocated %d paragraphs at real mode address <<%04X:%04X>>.\n",
	       pcount, RP_SEG(realptr), RP_OFF(realptr));
	printf("Writing to real mode segment.\n");
	WriteRealMem(realptr, test_str, sizeof(test_str));
	printf("Reading from real mode segment.\n");
	ReadRealMem(buff, realptr, sizeof(test_str));
	if(memcmp(buff, test_str, sizeof(test_str)) != 0)
	{
		printf("Can't read back string from real mode memory.\n");
	}
	if(!RealFree(realptr))
	{
		printf("RealFree failed -- error code %d.\n", 
	   	       GetLastError());	      
	}	
	else
	{
		printf("Real mode segment freed succesfully.\n");
	}
	if(!RealFree(realptr))
	{
		printf("Freeing segment twice failed as expected -- error code %d.\n",
		       GetLastError());
	}   
	else
	{	
		printf("Freeing segment twice did not failed as expected.\n");
	}
	realptr = RealAlloc(0xFFFF);
	if(realptr != 0)
	{
		printf("The call RealAlloc(0xFFFF) should have failed, but it didn't.\n");
	}
	else
	{
		printf("RealAlloc(0xFFFF) failed as expected -- error code %d.\n",
		       GetLastError());
	}
alloc_skip:;
	printf("\n");

	/* Test the real call function */

	printf("RealCall test.\n");
	pcount = 1024 / 16;
	stackp = RealAlloc(pcount);
	if(stackp == 0)
	{
		printf("RealAlloc failed -- error code %d.\n",
		       GetLastError());
		goto intr_skip;
	}
	stackp += pcount * 16;
	printf("The top of the real mode stack is located at <<%04X:%04X>>\n",
	       RP_SEG(stackp), RP_OFF(stackp));
	realptr = real_load("hello16", hello16);
	if(!realptr)
		goto call_skip;
	memset(&regs, 0, sizeof(regs));
	regs.r_flags = 0x202;
	regs.r_sp = RP_OFF(stackp);
	regs.r_ss = RP_SEG(stackp);
	fflush(stdout);
	CallCheck(RealCall(realptr, &rc, &regs, 0));
	real_unload(realptr);
	realptr = real_load("reg_test16", reg_test16);
	if(!realptr)
		goto call_skip;
	memset(&regs, 0, sizeof(regs));
	regs.r_flags = 0x202;
	regs.r_sp = RP_OFF(stackp);
	regs.r_ss = RP_SEG(stackp);
	regs.r_ax = 1;
	regs.r_bx = 2;
	regs.r_cx = 3;
	regs.r_dx = 4;
	regs.r_si = 5;
	regs.r_di = 6;
	regs.r_bp = 7;
	regs.r_ds = 8;
	regs.r_es = 9;
	print_regs("Input registers into reg_test16.", &regs);
	CallCheck(RealCall(realptr, &rc, &regs, 0));
	print_regs("Output registers from reg_test16.", &regs);
	real_unload(realptr);
	realptr = real_load("stack_test16", stack_test16);
	if(!realptr)
		goto call_skip;
	memset(&regs, 0, sizeof(regs));
	regs.r_flags = 0x202;
	regs.r_sp = RP_OFF(stackp);
	regs.r_ss = RP_SEG(stackp);
	print_regs("Input registers into stack_test16.", &regs);
	CallCheck(RealCall(realptr, &rc, &regs, 3, 0x1111, 0x2222, 0x3333));
	print_regs("Output registers from stack_test16.", &regs);
	memset(&regs, 0, sizeof(regs));
	regs.r_flags = 0x202;
	print_regs("Input registers into stack_test16.", &regs);
	CallCheck(RealCall(realptr, &rc, &regs, 3, 0x4444, 0x5555, 0x6666));
	print_regs("Output registers from stack_test16.", &regs);
	real_unload(realptr);
	realptr = real_load("pascal_test16", pascal_test16);
	if(!realptr)
		goto call_skip;
	memset(&regs, 0, sizeof(regs));
	regs.r_flags = 0x202;
	regs.r_sp = RP_OFF(stackp);
	regs.r_ss = RP_SEG(stackp);
	print_regs("Input registers into pascal_test16.", &regs);
	CallCheck(RealCall(realptr, &rc, &regs, -4, 0x7777, 0x8888, 0x9999, 
	          0xAAAA));
	print_regs("Output registers from pascal_test16.", &regs);
	real_unload(realptr);
call_skip:;
	printf("\n");

	/* Test the real interrupt function */

	memset(&regs, 0, sizeof(regs));
	regs.r_flags = 0x202;
	regs.r_ax = 0x3000;
	if(!RealIntr(0x21, &rc, &regs))
	{
		printf("RealIntr failed -- error code %d.\n",
		       GetLastError());
		goto intr_skip;
	}
	printf("DOS version number fetched via RealIntr = <<%d.%d>>.\n",
	       regs.r_ax & 0xFF, regs.r_ax >> 8);
	erc = (((DWORD)regs.r_dx) << 16) + regs.r_ax;
	if(rc != erc)
	{
		printf("Error -- DX:AX is not equal to return code.\n");
		printf("DX:AX = %08lX, return code = %08lX.\n",	erc, rc);
	}		       
intr_skip:;
	printf("\n");

	/* All done */

	printf("All done.\n");
	return 0;

}	


/*

real_load - Load a real mode function 

*/

real_load(namep, protptr)

char *namep;
char *protptr;

{

	REALPTR realptr;
	WORD pcount;
	WORD *sizep;

	sizep = ((WORD *)protptr) - 1;
	pcount = (*sizep + 15) / 16;
	realptr = RealAlloc(pcount);
	if(realptr == 0)
	{
		printf("RealAlloc failed -- error code %d.\n",
		       GetLastError());
		return 0L;
	}
	printf("Address of %s = <<%04X:%04X>>\n", namep,
	       RP_SEG(realptr), RP_OFF(realptr));
	printf("Size of %s = %d bytes\n", namep, *sizep);
	WriteRealMem(realptr, protptr, *sizep);

	return realptr;

}

CallCheck(flag)

BOOL flag;

{

	if(!flag)
	{
		printf("RealCall failed -- error code %d.\n",
		       GetLastError());
	}
	else
	{
		printf("Back to protected mode.\n");
	}

}


/*

print_regs - Print registers routine

*/

print_regs(headp, regsp)

char *headp;
REGS16 *regsp;

{

	printf("%s\n", headp);
	printf("AX=%04X  BX=%04X  CX=%04X  DX=%04X\n",
	       regsp->r_ax, regsp->r_bx, regsp->r_cx, regsp->r_dx);
	printf("SI=%04X  DI=%04X  BP=%04X\n",
	       regsp->r_si, regsp->r_di, regsp->r_bp);
	printf("DS=%04X  ES=%04X\n", regsp->r_ds, regsp->r_es);
	printf("SS:SP=<<%04X:%04X>>  FLAGS=<<%04X>>\n",
	       regsp->r_ss, regsp->r_sp, regsp->r_flags);

}    


/*

real_unload - Unload a real mode program

*/

real_unload(realptr)

REALPTR realptr;

{

	if(!RealFree(realptr))
	{
		printf("RealFree failed -- error code %d.\n", 
	   	       GetLastError());	      
	}	

}      
