diff options
Diffstat (limited to 'sysspec.c')
-rw-r--r-- | sysspec.c | 884 |
1 files changed, 884 insertions, 0 deletions
diff --git a/sysspec.c b/sysspec.c new file mode 100644 index 0000000..a97010d --- /dev/null +++ b/sysspec.c @@ -0,0 +1,884 @@ + +/* +** sysspec.c +** System-specific routines. +** +** BYTEmark (tm) +** BYTE's Native Mode Benchmarks +** Rick Grehan, BYTE Magazine +** +** Creation: +** Revision: 3/95;10/95 +** +** DISCLAIMER +** The source, executable, and documentation files that comprise +** the BYTEmark benchmarks are made available on an "as is" basis. +** This means that we at BYTE Magazine have made every reasonable +** effort to verify that the there are no errors in the source and +** executable code. We cannot, however, guarantee that the programs +** are error-free. Consequently, McGraw-HIll and BYTE Magazine make +** no claims in regard to the fitness of the source code, executable +** code, and documentation of the BYTEmark. +** Furthermore, BYTE Magazine, McGraw-Hill, and all employees +** of McGraw-Hill cannot be held responsible for any damages resulting +** from the use of this code or the results obtained from using +** this code. +*/ + +/*********************************** +** SYSTEM-SPECIFIC ROUTINES ** +************************************ +** +** These are the routines that provide functions that are +** system-specific. If the benchmarks are to be ported +** to new hardware/new O.S., this is the first place to +** start. +*/ +#include "sysspec.h" + +#ifdef DOS16 +#include <io.h> +#include <fcntl.h> +#include <sys\stat.h> +#endif +/********************************* +** MEMORY MANAGEMENT ROUTINES ** +*********************************/ + + +/**************************** +** AllocateMemory +** This routine returns a void pointer to a memory +** block. The size of the memory block is given in bytes +** as the first argument. This routine also returns an +** error code in the second argument. +** 10/95 Update: +** Added an associative array for memory alignment reasons. +** mem_array[2][MEM_ARRAY_SIZE] +** mem_array[0][n] = Actual address (from malloc) +** mem_array[1][n] = Aligned address +** Currently, mem_array[][] is only used if you use malloc; +** it is not used for the 16-bit DOS and MAC versions. +*/ +farvoid *AllocateMemory(unsigned long nbytes, /* # of bytes to alloc */ + int *errorcode) /* Returned error code */ +{ +#ifdef DOS16MEM +union REGS registers; +unsigned short nparas; /* # of paragraphs */ + +/* +** Set # of paragraphs to nbytes/16 +1. The +1 is a +** slop factor. +*/ +nparas=(unsigned short)(nbytes/16L) + 1; + +/* +** Set incoming registers. +*/ +registers.h.ah=0x48; /* Allocate memory */ +registers.x.bx=nparas; /* # of paragraphs */ + + +intdos(®isters,®isters); /* Call DOS */ + +/* +** See if things succeeded. +*/ +if(registers.x.cflag) +{ printf("error: %d Lgst: %d\n",registers.x.ax,registers.x.bx); + *errorcode=ERROR_MEMORY; + return((farvoid *)NULL); +} + +/* +** Create a farvoid pointer to return. +*/ +*errorcode=0; +return((farvoid *)MK_FP(registers.x.ax,0)); + +#endif + +#ifdef MACMEM +/* +** For MAC CodeWarrior, we'll use the MacOS NewPtr call +*/ +farvoid *returnval; +returnval=(farvoid *)NewPtr((Size)nbytes); +if(returnval==(farvoid *)NULL) + *errorcode=ERROR_MEMORY; +else + *errorcode=0; +return(returnval); +#endif + +#ifdef MALLOCMEM +/* +** Everyone else, its pretty straightforward, given +** that you use a 32-bit compiler which treats size_t as +** a 4-byte entity. +*/ +farvoid *returnval; /* Return value */ +ulong true_addr; /* True address */ +ulong adj_addr; /* Adjusted address */ + +returnval=(farvoid *)malloc((size_t)(nbytes+2L*(long)global_align)); +if(returnval==(farvoid *)NULL) + *errorcode=ERROR_MEMORY; +else + *errorcode=0; + +/* +** Check for alignment +*/ +adj_addr=true_addr=(ulong)returnval; +if(global_align==0) +{ + if(AddMemArray(true_addr, adj_addr)) + *errorcode=ERROR_MEMARRAY_FULL; + return(returnval); +} + +if(global_align==1) +{ + if(true_addr%2==0) adj_addr++; +} +else +{ + while(adj_addr%global_align!=0) ++adj_addr; + if(adj_addr%(global_align*2)==0) adj_addr+=global_align; +} +returnval=(void *)adj_addr; +if(AddMemArray(true_addr,adj_addr)) + *errorcode=ERROR_MEMARRAY_FULL; +return(returnval); +#endif + +} + + +/**************************** +** FreeMemory +** This is the reverse of AllocateMemory. The memory +** block passed in is freed. Should an error occur, +** that error is returned in errorcode. +*/ +void FreeMemory(farvoid *mempointer, /* Pointer to memory block */ + int *errorcode) +{ +#ifdef DOS16MEM +/* +** 16-bit DOS VERSION!! +*/ +unsigned int segment; +unsigned int offset; +union REGS registers; +struct SREGS sregisters; + +/* +** First get the segment/offset of the farvoid pointer. +*/ +segment=FP_SEG(mempointer); +offset=FP_OFF(mempointer); + +/* +** Align the segment properly. For as long as offset > 16, +** subtract 16 from offset and add 1 to segment. +*/ +while(offset>=16) +{ offset-=16; + segment++; +} + +/* +** Build the call to DOS +*/ +registers.h.ah=0x49; /* Free memory */ +sregisters.es=segment; + +intdosx(®isters,®isters,&sregisters); + +/* +** Check for error +*/ +if(registers.x.cflag) +{ *errorcode=ERROR_MEMORY; + return; +} + +*errorcode=0; +return; +#endif + +#ifdef MACMEM +DisposPtr((Ptr)mempointer); +*errorcode=0; +return; +#endif + +#ifdef MALLOCMEM +ulong adj_addr, true_addr; + +/* Locate item in memory array */ +adj_addr=(ulong)mempointer; +if(RemoveMemArray(adj_addr, &true_addr)) +{ *errorcode=ERROR_MEMARRAY_NFOUND; + return; +} +mempointer=(void *)true_addr; +free(mempointer); +*errorcode=0; +return; +#endif +} + +/**************************** +** MoveMemory +** Moves n bytes from a to b. Handles overlap. +** In most cases, this is just a memmove operation. +** But, not in DOS....noooo.... +*/ +void MoveMemory( farvoid *destination, /* Destination address */ + farvoid *source, /* Source address */ + unsigned long nbytes) +{ + +/* +++16-bit DOS VERSION+++ */ +#ifdef DOS16MEM + + FarDOSmemmove( destination, source, nbytes); + +#else + +memmove(destination, source, nbytes); + +#endif +} + +#ifdef DOS16MEM + +/**************************** +** FarDOSmemmove +** Performs the same function as memmove for DOS when +** the arrays are defined with far pointers. +*/ +void FarDOSmemmove(farvoid *destination, /* Destination pointer */ + farvoid *source, /* Source pointer */ + unsigned long nbytes) /* # of bytes to move */ +{ +unsigned char huge *uchsource; /* Temp source */ +unsigned char huge *uchdest; /* Temp destination */ +unsigned long saddr; /* Source "true" address */ +unsigned long daddr; /* Destination "true" address */ + + +/* +** Get unsigned char pointer equivalents +*/ +uchsource=(unsigned char huge *)source; +uchdest=(unsigned char huge *)destination; + +/* +** Calculate true address of source and destination and +** compare. +*/ +saddr=(unsigned long)(FP_SEG(source)*16 + FP_OFF(source)); +daddr=(unsigned long)(FP_SEG(destination)*16 + FP_OFF(destination)); + +if(saddr > daddr) +{ + /* + ** Source is greater than destination. + ** Use a series of standard move operations. + ** We'll move 65535 bytes at a time. + */ + while(nbytes>=65535L) + { _fmemmove((farvoid *)uchdest, + (farvoid *)uchsource, + (size_t) 65535); + uchsource+=65535; /* Advance pointers */ + uchdest+=65535; + nbytes-=65535; + } + + /* + ** Move remaining bytes + */ + if(nbytes!=0L) + _fmemmove((farvoid *)uchdest, + (farvoid *)uchsource, + (size_t)(nbytes & 0xFFFF)); + +} +else +{ + /* + ** Destination is greater than source. + ** Advance pointers to the end of their + ** respective blocks. + */ + uchsource+=nbytes; + uchdest+=nbytes; + + /* + ** Again, move 65535 bytes at a time. However, + ** "back" the pointers up before doing the + ** move. + */ + while(nbytes>=65535L) + { + uchsource-=65535; + uchdest-=65535; + _fmemmove((farvoid *)uchdest, + (farvoid *)uchsource, + (size_t) 65535); + nbytes-=65535; + } + + /* + ** Move remaining bytes. + */ + if(nbytes!=0L) + { uchsource-=nbytes; + uchdest-=nbytes; + _fmemmove((farvoid *)uchdest, + (farvoid *)uchsource, + (size_t)(nbytes & 0xFFFF)); + } +} +return; +} +#endif + +/*********************************** +** MEMORY ARRAY HANDLING ROUTINES ** +***********************************/ +/**************************** +** InitMemArray +** Initialize the memory array. This simply amounts to +** setting mem_array_ents to zero, indicating that there +** isn't anything in the memory array. +*/ +void InitMemArray(void) +{ +mem_array_ents=0; +return; +} + +/*************************** +** AddMemArray +** Add a pair of items to the memory array. +** true_addr is the true address (mem_array[0][n]) +** adj_addr is the adjusted address (mem_array[0][n]) +** Returns 0 if ok +** -1 if not enough room +*/ +int AddMemArray(ulong true_addr, + ulong adj_addr) +{ +if(mem_array_ents>=MEM_ARRAY_SIZE) + return(-1); + +mem_array[0][mem_array_ents]=true_addr; +mem_array[1][mem_array_ents]=adj_addr; +mem_array_ents++; +return(0); +} + +/************************* +** RemoveMemArray +** Given an adjusted address value (mem_array[1][n]), locate +** the entry and remove it from the mem_array. +** Also returns the associated true address. +** Returns 0 if ok +** -1 if not found. +*/ +int RemoveMemArray(ulong adj_addr,ulong *true_addr) +{ +int i,j; + +/* Locate the item in the array. */ +for(i=0;i<mem_array_ents;i++) + if(mem_array[1][i]==adj_addr) + { /* Found it..bubble stuff down */ + *true_addr=mem_array[0][i]; + j=i; + while(j+1<mem_array_ents) + { mem_array[0][j]=mem_array[0][j+1]; + mem_array[1][j]=mem_array[1][j+1]; + j++; + } + mem_array_ents--; + return(0); /* Return if found */ + } + +/* If we made it here...something's wrong...show error */ +return(-1); +} + +/********************************** +** FILE HANDLING ROUTINES ** +**********************************/ + +/**************************** +** CreateFile +** This routine accepts a filename for an argument and +** creates that file in the current directory (unless the +** name contains a path that overrides the current directory). +** Note that the routine does not OPEN the file. +** If the file exists, it is truncated to length 0. +*/ +void CreateFile(char *filename, + int *errorcode) +{ + +#ifdef DOS16 +/* +** DOS VERSION!! +*/ +int fhandle; /* File handle used internally */ + +fhandle=open(filename,O_CREAT | O_TRUNC, S_IREAD | S_IWRITE); + +if(fhandle==-1) + *errorcode=ERROR_FILECREATE; +else + *errorcode=0; + +/* +** Since all we're doing here is creating the file, +** go ahead and close it. +*/ +close(fhandle); + +return; +#endif + +#ifdef LINUX +FILE *fhandle; /* File handle used internally */ + +fhandle=fopen(filename,"w"); + +if(fhandle==NULL) + *errorcode=ERROR_FILECREATE; +else + *errorcode=0; + +/* +** Since all we're doing here is creating the file, +** go ahead and close it. +*/ +fclose(fhandle); + +return; +#endif +} + +/**************************** +** bmOpenFile +** Opens the file given by fname, returning its handle. +** If an error occurs, returns its code in errorcode. +** The file is opened in read-write exclusive mode. +*/ +#ifdef DOS16 +/* +** DOS VERSION!! +*/ + +int bmOpenFile(char *fname, /* File name */ + int *errorcode) /* Error code returned */ +{ + +int fhandle; /* Returned file handle */ + +fhandle=open(fname,O_BINARY | O_RDWR, S_IREAD | S_IWRITE); + +if(fhandle==-1) + *errorcode=ERROR_FILEOPEN; +else + *errorcode=0; + +return(fhandle); +} +#endif + + +#ifdef LINUX + +FILE *bmOpenFile(char *fname, /* File name */ + int *errorcode) /* Error code returned */ +{ + +FILE *fhandle; /* Returned file handle */ + +fhandle=fopen(fname,"w+"); + +if(fhandle==NULL) + *errorcode=ERROR_FILEOPEN; +else + *errorcode=0; + +return(fhandle); +} +#endif + + +/**************************** +** CloseFile +** Closes the file identified by fhandle. +** A more inocuous routine there never was. +*/ +#ifdef DOS16 +/* +** DOS VERSION!!! +*/ +void CloseFile(int fhandle, /* File handle */ + int *errorcode) /* Returned error code */ +{ + +close(fhandle); +*errorcode=0; +return; +} +#endif +#ifdef LINUX +void CloseFile(FILE *fhandle, /* File handle */ + int *errorcode) /* Returned error code */ +{ +fclose(fhandle); +*errorcode=0; +return; +} +#endif + +/**************************** +** readfile +** Read bytes from an opened file. This routine +** is a combination seek-and-read. +** Note that this routine expects the offset to be from +** the beginning of the file. +*/ +#ifdef DOS16 +/* +** DOS VERSION!! +*/ + +void readfile(int fhandle, /* File handle */ + unsigned long offset, /* Offset into file */ + unsigned long nbytes, /* # of bytes to read */ + void *buffer, /* Buffer to read into */ + int *errorcode) /* Returned error code */ +{ + +long newoffset; /* New offset by lseek */ +int readcode; /* Return code from read */ + +/* +** Presume success. +*/ +*errorcode=0; + +/* +** Seek to the proper offset. +*/ +newoffset=lseek(fhandle,(long)offset,SEEK_SET); +if(newoffset==-1L) +{ *errorcode=ERROR_FILESEEK; + return; +} + +/* +** Do the read. +*/ +readcode=read(fhandle,buffer,(unsigned)(nbytes & 0xFFFF)); +if(readcode==-1) + *errorcode=ERROR_FILEREAD; + +return; +} +#endif +#ifdef LINUX +void readfile(FILE *fhandle, /* File handle */ + unsigned long offset, /* Offset into file */ + unsigned long nbytes, /* # of bytes to read */ + void *buffer, /* Buffer to read into */ + int *errorcode) /* Returned error code */ +{ + +long newoffset; /* New offset by fseek */ +size_t nelems; /* Expected return code from read */ +size_t readcode; /* Actual return code from read */ + +/* +** Presume success. +*/ +*errorcode=0; + +/* +** Seek to the proper offset. +*/ +newoffset=fseek(fhandle,(long)offset,SEEK_SET); +if(newoffset==-1L) +{ *errorcode=ERROR_FILESEEK; + return; +} + +/* +** Do the read. +*/ +nelems=(size_t)(nbytes & 0xFFFF); +readcode=fread(buffer,(size_t)1,nelems,fhandle); +if(readcode!=nelems) + *errorcode=ERROR_FILEREAD; + +return; +} +#endif + +/**************************** +** writefile +** writes bytes to an opened file. This routine is +** a combination seek-and-write. +** Note that this routine expects the offset to be from +** the beinning of the file. +*/ +#ifdef DOS16 +/* +** DOS VERSION!! +*/ + +void writefile(int fhandle, /* File handle */ + unsigned long offset, /* Offset into file */ + unsigned long nbytes, /* # of bytes to read */ + void *buffer, /* Buffer to read into */ + int *errorcode) /* Returned error code */ +{ + +long newoffset; /* New offset by lseek */ +int writecode; /* Return code from write */ + +/* +** Presume success. +*/ +*errorcode=0; + +/* +** Seek to the proper offset. +*/ +newoffset=lseek(fhandle,(long)offset,SEEK_SET); +if(newoffset==-1L) +{ *errorcode=ERROR_FILESEEK; + return; +} + +/* +** Do the write. +*/ +writecode=write(fhandle,buffer,(unsigned)(nbytes & 0xFFFF)); +if(writecode==-1) + *errorcode=ERROR_FILEWRITE; + +return; +} +#endif + +#ifdef LINUX + +void writefile(FILE *fhandle, /* File handle */ + unsigned long offset, /* Offset into file */ + unsigned long nbytes, /* # of bytes to read */ + void *buffer, /* Buffer to read into */ + int *errorcode) /* Returned error code */ +{ + +long newoffset; /* New offset by lseek */ +size_t nelems; /* Expected return code from write */ +size_t writecode; /* Actual return code from write */ + +/* +** Presume success. +*/ +*errorcode=0; + +/* +** Seek to the proper offset. +*/ +newoffset=fseek(fhandle,(long)offset,SEEK_SET); +if(newoffset==-1L) +{ *errorcode=ERROR_FILESEEK; + return; +} + +/* +** Do the write. +*/ +nelems=(size_t)(nbytes & 0xFFFF); +writecode=fwrite(buffer,(size_t)1,nelems,fhandle); +if(writecode==nelems) + *errorcode=ERROR_FILEWRITE; + +return; +} +#endif + + +/******************************** +** ERROR HANDLING ROUTINES ** +********************************/ + +/**************************** +** ReportError +** Report error message condition. +*/ +void ReportError(char *errorcontext, /* Error context string */ + int errorcode) /* Error code number */ +{ + +/* +** Display error context +*/ +printf("ERROR CONDITION\nContext: %s\n",errorcontext); + +/* +** Display code +*/ +printf("Code: %d",errorcode); + +return; +} + +/**************************** +** ErrorExit +** Peforms an exit from an error condition. +*/ +void ErrorExit() +{ + +/* +** For profiling on the Mac with MetroWerks -- 11/17/94 RG +** Have to do this to turn off profiler. +*/ +#ifdef MACCWPROF +#if __profile__ +ProfilerTerm(); +#endif +#endif + +/* +** FOR NOW...SIMPLE EXIT +*/ +exit(1); +} + +/***************************** +** STOPWATCH ROUTINES ** +*****************************/ + +/**************************** +** StartStopwatch +** Starts a software stopwatch. Returns the first value of +** the stopwatch in ticks. +*/ +unsigned long StartStopwatch() +{ +#ifdef MACTIMEMGR +/* +** For Mac code warrior, use timer. In this case, what we return is really +** a dummy value. +*/ +InsTime((QElemPtr)&myTMTask); +PrimeTime((QElemPtr)&myTMTask,-MacHSTdelay); +return((unsigned long)1); +#else +#ifdef WIN31TIMER +/* +** Win 3.x timer returns a DWORD, which we coax into a long. +*/ +_Call16(lpfn,"p",&win31tinfo); +return((unsigned long)win31tinfo.dwmsSinceStart); +#else +return((unsigned long)clock()); +#endif +#endif +} + +/**************************** +** StopStopwatch +** Stops the software stopwatch. Expects as an input argument +** the stopwatch start time. +*/ +unsigned long StopStopwatch(unsigned long startticks) +{ + +#ifdef MACTIMEMGR +/* +** For Mac code warrior...ignore startticks. Return val. in microseconds +*/ +RmvTime((QElemPtr)&myTMTask); +return((unsigned long)(MacHSTdelay+myTMTask.tmCount-MacHSTohead)); +#else +#ifdef WIN31TIMER +_Call16(lpfn,"p",&win31tinfo); +return((unsigned long)win31tinfo.dwmsSinceStart-startticks); +#else +return((unsigned long)clock()-startticks); +#endif +#endif +} + +/**************************** +** TicksToSecs +** Converts ticks to seconds. Converts ticks to integer +** seconds, discarding any fractional amount. +*/ +unsigned long TicksToSecs(unsigned long tickamount) +{ +#ifdef CLOCKWCT +return((unsigned long)(tickamount/CLK_TCK)); +#endif + +#ifdef MACTIMEMGR +/* +++ MAC time manager version (using timer in microseconds) +++ */ +return((unsigned long)(tickamount/1000000)); +#endif + +#ifdef CLOCKWCPS +/* Everybody else */ +return((unsigned long)(tickamount/CLOCKS_PER_SEC)); +#endif + +#ifdef WIN31TIMER +/* Each tick is 840 nanoseconds */ +return((unsigned long)(tickamount/1000L)); +#endif + +} + +/**************************** +** TicksToFracSecs +** Converts ticks to fractional seconds. In other words, +** this returns the exact conversion from ticks to +** seconds. +*/ +double TicksToFracSecs(unsigned long tickamount) +{ +#ifdef CLOCKWCT +return((double)tickamount/(double)CLK_TCK); +#endif + +#ifdef MACTIMEMGR +/* +++ MAC time manager version +++ */ +return((double)tickamount/(double)1000000); +#endif + +#ifdef CLOCKWCPS +/* Everybody else */ +return((double)tickamount/(double)CLOCKS_PER_SEC); +#endif + +#ifdef WIN31TIMER +/* Using 840 nanosecond ticks */ +return((double)tickamount/(double)1000); +#endif +} + |