Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. #include <errno.h>
  21. #include <unistd.h>
  22. #include <signal.h>
  23. #include <stdlib.h>
  24. #include <limits.h>
  25. #include <sys/time.h>
  26. #include <sys/types.h>
  27. #include <dir.h>
  28. #include <unistd.h>
  29. #include <fcntl.h>
  30. #include <stdarg.h>
  31. #include <stdio.h>
  32. #include <sys/stat.h>
  33. #include <string.h>
  34. #include <dpmi.h>
  35. #include <sys/nearptr.h>
  36. #include <conio.h>
  37.  
  38. #include "quakedef.h"
  39. #include "dosisms.h"
  40.  
  41. #define MINIMUM_WIN_MEMORY                      0x800000
  42. #define MINIMUM_WIN_MEMORY_LEVELPAK     (MINIMUM_WIN_MEMORY + 0x100000)
  43.  
  44. int                     end_of_memory;
  45. qboolean        lockmem, lockunlockmem, unlockmem;
  46. static int      win95;
  47.  
  48. #define STDOUT  1
  49.  
  50. #define KEYBUF_SIZE     256
  51. static unsigned char    keybuf[KEYBUF_SIZE];
  52. static int                              keybuf_head=0;
  53. static int                              keybuf_tail=0;
  54.  
  55. static quakeparms_t     quakeparms;
  56. int                                     sys_checksum;
  57. static double           curtime = 0.0;
  58. static double           lastcurtime = 0.0;
  59. static double           oldtime = 0.0;
  60.  
  61. static qboolean         isDedicated;
  62.  
  63. static int                      minmem;
  64.  
  65. float                           fptest_temp;
  66.  
  67. extern char     start_of_memory __asm__("start");
  68.  
  69. //=============================================================================
  70.  
  71. // this is totally dependent on cwsdpmi putting the stack right after tge
  72. // global data
  73.  
  74. // This does evil things in a Win95 DOS box!!!
  75. #if 0
  76. extern byte end;
  77. #define CHECKBYTE       0xed
  78. void Sys_InitStackCheck (void)
  79. {
  80.         int             i;
  81.        
  82.         for (i=0 ; i<128*1024 ; i++)
  83.                 (&end)[i] = CHECKBYTE;
  84. }
  85.  
  86. void Sys_StackCheck (void)
  87. {
  88.         int             i;
  89.        
  90.         for (i=0 ; i<128*1024 ; i++)
  91.                 if ( (&end)[i] != CHECKBYTE )
  92.                         break;
  93.        
  94.         Con_Printf ("%i undisturbed stack bytes\n", i);
  95.         if (end != CHECKBYTE)
  96.                 Sys_Error ("System stack overflow!");
  97. }
  98. #endif
  99.  
  100. //=============================================================================
  101.  
  102. byte        scantokey[128] =
  103.                                         {
  104. //  0           1       2       3       4       5       6       7
  105. //  8           9       A       B       C       D       E       F
  106.         0  ,    27,     '1',    '2',    '3',    '4',    '5',    '6',
  107.         '7',    '8',    '9',    '0',    '-',    '=',    K_BACKSPACE, 9, // 0
  108.         'q',    'w',    'e',    'r',    't',    'y',    'u',    'i',
  109.         'o',    'p',    '[',    ']',    13 ,    K_CTRL,'a',  's',      // 1
  110.         'd',    'f',    'g',    'h',    'j',    'k',    'l',    ';',
  111.         '\'' ,    '`',    K_SHIFT,'\\',  'z',    'x',    'c',    'v',      // 2
  112.         'b',    'n',    'm',    ',',    '.',    '/',    K_SHIFT,'*',
  113.         K_ALT,' ',   0  ,    K_F1, K_F2, K_F3, K_F4, K_F5,   // 3
  114.         K_F6, K_F7, K_F8, K_F9, K_F10,0  ,    0  , K_HOME,
  115.         K_UPARROW,K_PGUP,'-',K_LEFTARROW,'5',K_RIGHTARROW,'+',K_END, //4
  116.         K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0,             0,              K_F11,
  117.         K_F12,0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,        // 5
  118.         0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,
  119.         0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,        // 6
  120.         0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,
  121.         0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0         // 7
  122.                                         };
  123.  
  124. byte        shiftscantokey[128] =
  125.                                         {
  126. //  0           1       2       3       4       5       6       7
  127. //  8           9       A       B       C       D       E       F
  128.         0  ,    27,     '!',    '@',    '#',    '$',    '%',    '^',
  129.         '&',    '*',    '(',    ')',    '_',    '+',    K_BACKSPACE, 9, // 0
  130.         'Q',    'W',    'E',    'R',    'T',    'Y',    'U',    'I',
  131.         'O',    'P',    '{',    '}',    13 ,    K_CTRL,'A',  'S',      // 1
  132.         'D',    'F',    'G',    'H',    'J',    'K',    'L',    ':',
  133.         '"' ,    '~',    K_SHIFT,'|',  'Z',    'X',    'C',    'V',      // 2
  134.         'B',    'N',    'M',    '<',    '>',    '?',    K_SHIFT,'*',
  135.         K_ALT,' ',   0  ,    K_F1, K_F2, K_F3, K_F4, K_F5,   // 3
  136.         K_F6, K_F7, K_F8, K_F9, K_F10,0  ,    0  , K_HOME,
  137.         K_UPARROW,K_PGUP,'_',K_LEFTARROW,'%',K_RIGHTARROW,'+',K_END, //4
  138.         K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0,             0,              K_F11,
  139.         K_F12,0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,        // 5
  140.         0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,
  141.         0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,        // 6
  142.         0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,
  143.         0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0         // 7
  144.                                         };
  145.  
  146. void TrapKey(void)
  147. {
  148. //      static int ctrl=0;
  149.         keybuf[keybuf_head] = dos_inportb(0x60);
  150.         dos_outportb(0x20, 0x20);
  151.         /*
  152.         if (scantokey[keybuf[keybuf_head]&0x7f] == K_CTRL)
  153.                 ctrl=keybuf[keybuf_head]&0x80;
  154.         if (ctrl && scantokey[keybuf[keybuf_head]&0x7f] == 'c')
  155.                 Sys_Error("ctrl-c hit\n");
  156.         */
  157.         keybuf_head = (keybuf_head + 1) & (KEYBUF_SIZE-1);
  158. }
  159.  
  160. #define SC_UPARROW              0x48
  161. #define SC_DOWNARROW    0x50
  162. #define SC_LEFTARROW            0x4b
  163. #define SC_RIGHTARROW   0x4d
  164. #define SC_LEFTSHIFT   0x2a
  165. #define SC_RIGHTSHIFT   0x36
  166. #define SC_RIGHTARROW   0x4d
  167.  
  168. void MaskExceptions (void);
  169. void Sys_InitFloatTime (void);
  170. void Sys_PushFPCW_SetHigh (void);
  171. void Sys_PopFPCW (void);
  172.  
  173. #define LEAVE_FOR_CACHE (512*1024)              //FIXME: tune
  174. #define LOCKED_FOR_MALLOC (128*1024)    //FIXME: tune
  175.  
  176.  
  177. void Sys_DetectWin95 (void)
  178. {
  179.         __dpmi_regs                             r;
  180.  
  181.         r.x.ax = 0x160a;                /* Get Windows Version */
  182.         __dpmi_int(0x2f, &r);
  183.  
  184.         if(r.x.ax || r.h.bh < 4)        /* Not windows or earlier than Win95 */
  185.         {
  186.                 win95 = 0;
  187.                 lockmem = true;
  188.                 lockunlockmem = false;
  189.                 unlockmem = true;
  190.         }
  191.         else
  192.         {
  193.                 win95 = 1;
  194.                 lockunlockmem = COM_CheckParm ("-winlockunlock");
  195.  
  196.                 if (lockunlockmem)
  197.                         lockmem = true;
  198.                 else
  199.                         lockmem = COM_CheckParm ("-winlock");
  200.  
  201.                 unlockmem = lockmem && !lockunlockmem;
  202.         }
  203. }
  204.  
  205.  
  206. void *dos_getmaxlockedmem(int *size)
  207. {
  208.         __dpmi_free_mem_info    meminfo;
  209.         __dpmi_meminfo                  info;
  210.         int                                             working_size;
  211.         void                                    *working_memory;
  212.         int                                             last_locked;
  213.         int                                             extra,  i, j, allocsize;
  214.         static char                             *msg = "Locking data...";
  215.         int                                             m, n;
  216.         byte                                    *x;
  217.  
  218. // first lock all the current executing image so the locked count will
  219. // be accurate.  It doesn't hurt to lock the memory multiple times
  220.         last_locked = __djgpp_selector_limit + 1;
  221.         info.size = last_locked - 4096;
  222.         info.address = __djgpp_base_address + 4096;
  223.  
  224.         if (lockmem)
  225.         {
  226.                 if(__dpmi_lock_linear_region(&info))
  227.                 {
  228.                         Sys_Error ("Lock of current memory at 0x%lx for %ldKb failed!\n",
  229.                                                 info.address, info.size/1024);
  230.                 }
  231.         }
  232.  
  233.         __dpmi_get_free_memory_information(&meminfo);
  234.  
  235.         if (!win95)             /* Not windows or earlier than Win95 */
  236.         {
  237.                 working_size = meminfo.maximum_locked_page_allocation_in_pages * 4096;
  238.         }
  239.         else
  240.         {
  241.                 working_size = meminfo.largest_available_free_block_in_bytes -
  242.                                 LEAVE_FOR_CACHE;
  243.         }
  244.  
  245.         working_size &= ~0xffff;                /* Round down to 64K */
  246.         working_size += 0x10000;
  247.  
  248.         do
  249.         {
  250.                 working_size -= 0x10000;                /* Decrease 64K and try again */
  251.                 working_memory = sbrk(working_size);
  252.         } while (working_memory == (void *)-1);
  253.  
  254.         extra = 0xfffc - ((unsigned)sbrk(0) & 0xffff);
  255.  
  256.         if (extra > 0)
  257.         {
  258.                 sbrk(extra);
  259.                 working_size += extra;
  260.         }
  261.  
  262. // now grab the memory
  263.         info.address = last_locked + __djgpp_base_address;
  264.  
  265.         if (!win95)
  266.         {
  267.             info.size = __djgpp_selector_limit + 1 - last_locked;
  268.  
  269.                 while (info.size > 0 && __dpmi_lock_linear_region(&info))
  270.                 {
  271.                         info.size -= 0x1000;
  272.                         working_size -= 0x1000;
  273.                         sbrk(-0x1000);
  274.                 }
  275.         }
  276.         else
  277.         {                       /* Win95 section */
  278.                 j = COM_CheckParm("-winmem");
  279.  
  280.                 if (standard_quake)
  281.                         minmem = MINIMUM_WIN_MEMORY;
  282.                 else
  283.                         minmem = MINIMUM_WIN_MEMORY_LEVELPAK;
  284.  
  285.                 if (j)
  286.                 {
  287.                         allocsize = ((int)(Q_atoi(com_argv[j+1]))) * 0x100000 +
  288.                                         LOCKED_FOR_MALLOC;
  289.  
  290.                         if (allocsize < (minmem + LOCKED_FOR_MALLOC))
  291.                                 allocsize = minmem + LOCKED_FOR_MALLOC;
  292.                 }
  293.                 else
  294.                 {
  295.                         allocsize = minmem + LOCKED_FOR_MALLOC;
  296.                 }
  297.  
  298.                 if (!lockmem)
  299.                 {
  300.                 // we won't lock, just sbrk the memory
  301.                         info.size = allocsize;
  302.                         goto UpdateSbrk;
  303.                 }
  304.  
  305.                 // lock the memory down
  306.                 write (STDOUT, msg, strlen (msg));
  307.  
  308.                 for (j=allocsize ; j>(minmem + LOCKED_FOR_MALLOC) ;
  309.                          j -= 0x100000)
  310.                 {
  311.                         info.size = j;
  312.        
  313.                         if (!__dpmi_lock_linear_region(&info))
  314.                                 goto Locked;
  315.        
  316.                         write (STDOUT, ".", 1);
  317.                 }
  318.  
  319.         // finally, try with the absolute minimum amount
  320.                 for (i=0 ; i<10 ; i++)
  321.                 {
  322.                         info.size = minmem + LOCKED_FOR_MALLOC;
  323.  
  324.                         if (!__dpmi_lock_linear_region(&info))
  325.                                 goto Locked;
  326.                 }
  327.  
  328.                 Sys_Error ("Can't lock memory; %d Mb lockable RAM required. "
  329.                                    "Try shrinking smartdrv.", info.size / 0x100000);
  330.  
  331. Locked:
  332.  
  333. UpdateSbrk:
  334.  
  335.                 info.address += info.size;
  336.                 info.address -= __djgpp_base_address + 4; // ending point, malloc align
  337.                 working_size = info.address - (int)working_memory;
  338.                 sbrk(info.address-(int)sbrk(0));                // negative adjustment
  339.         }
  340.  
  341.  
  342.         if (lockunlockmem)
  343.         {
  344.                 __dpmi_unlock_linear_region (&info);
  345.                 printf ("Locked and unlocked %d Mb data\n", working_size / 0x100000);
  346.         }
  347.         else if (lockmem)
  348.         {
  349.                 printf ("Locked %d Mb data\n", working_size / 0x100000);
  350.         }
  351.         else
  352.         {
  353.                 printf ("Allocated %d Mb data\n", working_size / 0x100000);
  354.         }
  355.  
  356. // touch all the memory to make sure it's there. The 16-page skip is to
  357. // keep Win 95 from thinking we're trying to page ourselves in (we are
  358. // doing that, of course, but there's no reason we shouldn't)
  359.         x = (byte *)working_memory;
  360.  
  361.         for (n=0 ; n<4 ; n++)
  362.         {
  363.                 for (m=0 ; m<(working_size - 16 * 0x1000) ; m += 4)
  364.                 {
  365.                         sys_checksum += *(int *)&x[m];
  366.                         sys_checksum += *(int *)&x[m + 16 * 0x1000];
  367.                 }
  368.         }
  369.  
  370. // give some of what we locked back for malloc before returning.  Done
  371. // by cheating and passing a negative value to sbrk
  372.         working_size -= LOCKED_FOR_MALLOC;
  373.         sbrk( -(LOCKED_FOR_MALLOC));
  374.         *size = working_size;
  375.         return working_memory;
  376. }
  377.  
  378.  
  379. /*
  380. ============
  381. Sys_FileTime
  382.  
  383. returns -1 if not present
  384. ============
  385. */
  386. int     Sys_FileTime (char *path)
  387. {
  388.         struct  stat    buf;
  389.        
  390.         if (stat (path,&buf) == -1)
  391.                 return -1;
  392.        
  393.         return buf.st_mtime;
  394. }
  395.  
  396. void Sys_mkdir (char *path)
  397. {
  398.         mkdir (path, 0777);
  399. }
  400.  
  401.  
  402. void Sys_Sleep(void)
  403. {
  404. }
  405.  
  406.  
  407. char *Sys_ConsoleInput(void)
  408. {
  409.         static char     text[256];
  410.         static int      len = 0;
  411.         char            ch;
  412.  
  413.         if (!isDedicated)
  414.                 return NULL;
  415.  
  416.         if (! kbhit())
  417.                 return NULL;
  418.  
  419.         ch = getche();
  420.  
  421.         switch (ch)
  422.         {
  423.                 case '\r':
  424.                         putch('\n');
  425.                         if (len)
  426.                         {
  427.                                 text[len] = 0;
  428.                                 len = 0;
  429.                                 return text;
  430.                         }
  431.                         break;
  432.  
  433.                 case '\b':
  434.                         putch(' ');
  435.                         if (len)
  436.                         {
  437.                                 len--;
  438.                                 putch('\b');
  439.                         }
  440.                         break;
  441.  
  442.                 default:
  443.                         text[len] = ch;
  444.                         len = (len + 1) & 0xff;
  445.                         break;
  446.         }
  447.  
  448.         return NULL;
  449. }
  450.  
  451. void Sys_Init(void)
  452. {
  453.  
  454.         MaskExceptions ();
  455.  
  456.         Sys_SetFPCW ();
  457.  
  458.     dos_outportb(0x43, 0x34); // set system timer to mode 2
  459.     dos_outportb(0x40, 0);    // for the Sys_FloatTime() function
  460.     dos_outportb(0x40, 0);
  461.  
  462.         Sys_InitFloatTime ();
  463.  
  464.         _go32_interrupt_stack_size = 4 * 1024;;
  465.         _go32_rmcb_stack_size = 4 * 1024;
  466. }
  467.  
  468. void Sys_Shutdown(void)
  469. {
  470.         if (!isDedicated)
  471.                 dos_restoreintr(9);
  472.  
  473.         if (unlockmem)
  474.         {
  475.                 dos_unlockmem (&start_of_memory,
  476.                                            end_of_memory - (int)&start_of_memory);
  477.                 dos_unlockmem (quakeparms.membase, quakeparms.memsize);
  478.         }
  479. }
  480.  
  481.  
  482. #define SC_RSHIFT       0x36
  483. #define SC_LSHIFT       0x2a
  484. void Sys_SendKeyEvents (void)
  485. {
  486.         int k, next;
  487.         int outkey;
  488.  
  489. // get key events
  490.  
  491.         while (keybuf_head != keybuf_tail)
  492.         {
  493.  
  494.                 k = keybuf[keybuf_tail++];
  495.                 keybuf_tail &= (KEYBUF_SIZE-1);
  496.  
  497.                 if (k==0xe0)
  498.                         continue;               // special / pause keys
  499.                 next = keybuf[(keybuf_tail-2)&(KEYBUF_SIZE-1)];
  500.                 if (next == 0xe1)
  501.                         continue;                               // pause key bullshit
  502.                 if (k==0xc5 && next == 0x9d)
  503.                 {
  504.                         Key_Event (K_PAUSE, true);
  505.                         continue;
  506.                 }
  507.  
  508.                 // extended keyboard shift key bullshit
  509.                 if ( (k&0x7f)==SC_LSHIFT || (k&0x7f)==SC_RSHIFT )
  510.                 {
  511.                         if ( keybuf[(keybuf_tail-2)&(KEYBUF_SIZE-1)]==0xe0 )
  512.                                 continue;
  513.                         k &= 0x80;
  514.                         k |= SC_RSHIFT;
  515.                 }
  516.  
  517.                 if (k==0xc5 && keybuf[(keybuf_tail-2)&(KEYBUF_SIZE-1)] == 0x9d)
  518.                         continue; // more pause bullshit
  519.  
  520.                 outkey = scantokey[k & 0x7f];
  521.  
  522.                 if (k & 0x80)
  523.                         Key_Event (outkey, false);
  524.                 else
  525.                         Key_Event (outkey, true);
  526.  
  527.         }
  528.  
  529. }
  530.  
  531.  
  532. // =======================================================================
  533. // General routines
  534. // =======================================================================
  535.  
  536. /*
  537. ================
  538. Sys_Printf
  539. ================
  540. */
  541.  
  542. void Sys_Printf (char *fmt, ...)
  543. {
  544.         va_list         argptr;
  545.         char            text[1024];
  546.        
  547.         va_start (argptr,fmt);
  548.         vsprintf (text,fmt,argptr);
  549.         va_end (argptr);
  550.  
  551.         if (cls.state == ca_dedicated)
  552.                 fprintf(stderr, "%s", text);
  553. }
  554.  
  555. void Sys_AtExit (void)
  556. {
  557.  
  558. // shutdown only once (so Sys_Error can call this function to shutdown, then
  559. // print the error message, then call exit without exit calling this function
  560. // again)
  561.         Sys_Shutdown();
  562. }
  563.  
  564.  
  565. void Sys_Quit (void)
  566. {
  567.         byte    screen[80*25*2];
  568.         byte    *d;
  569.         char                    ver[6];
  570.         int                     i;
  571.        
  572.  
  573. // load the sell screen before shuting everything down
  574.         if (registered.value)
  575.                 d = COM_LoadHunkFile ("end2.bin");
  576.         else
  577.                 d = COM_LoadHunkFile ("end1.bin");
  578.         if (d)
  579.                 memcpy (screen, d, sizeof(screen));
  580.  
  581. // write the version number directly to the end screen
  582.         sprintf (ver, " v%4.2f", VERSION);
  583.         for (i=0 ; i<6 ; i++)
  584.                 screen[0*80*2 + 72*2 + i*2] = ver[i];
  585.  
  586.         Host_Shutdown();
  587.  
  588. // do the text mode sell screen
  589.         if (d)
  590.         {
  591.                 memcpy ((void *)real2ptr(0xb8000), screen,80*25*2);
  592.        
  593.         // set text pos
  594.                 regs.x.ax = 0x0200;
  595.                 regs.h.bh = 0;
  596.                 regs.h.dl = 0;
  597.                 regs.h.dh = 22;
  598.                 dos_int86 (0x10);
  599.         }
  600.         else
  601.                 printf ("couldn't load endscreen.\n");
  602.  
  603.         exit(0);
  604. }
  605.  
  606. void Sys_Error (char *error, ...)
  607. {
  608.     va_list     argptr;
  609.     char        string[1024];
  610.    
  611.     va_start (argptr,error);
  612.     vsprintf (string,error,argptr);
  613.     va_end (argptr);
  614.  
  615.         Host_Shutdown();
  616.         fprintf(stderr, "Error: %s\n", string);
  617. // Sys_AtExit is called by exit to shutdown the system
  618.         exit(0);
  619. }
  620.  
  621.  
  622. int Sys_FileOpenRead (char *path, int *handle)
  623. {
  624.         int     h;
  625.         struct stat     fileinfo;
  626.    
  627.         h = open (path, O_RDONLY|O_BINARY, 0666);
  628.         *handle = h;
  629.         if (h == -1)
  630.                 return -1;
  631.        
  632.         if (fstat (h,&fileinfo) == -1)
  633.                 Sys_Error ("Error fstating %s", path);
  634.  
  635.         return fileinfo.st_size;
  636. }
  637.  
  638. int Sys_FileOpenWrite (char *path)
  639. {
  640.         int     handle;
  641.  
  642.         umask (0);
  643.        
  644.         handle = open(path,O_RDWR | O_BINARY | O_CREAT | O_TRUNC
  645.         , 0666);
  646.  
  647.         if (handle == -1)
  648.                 Sys_Error ("Error opening %s: %s", path,strerror(errno));
  649.  
  650.         return handle;
  651. }
  652.  
  653. void Sys_FileClose (int handle)
  654. {
  655.         close (handle);
  656. }
  657.  
  658. void Sys_FileSeek (int handle, int position)
  659. {
  660.         lseek (handle, position, SEEK_SET);
  661. }
  662.  
  663. int Sys_FileRead (int handle, void *dest, int count)
  664. {
  665.    return read (handle, dest, count);
  666. }
  667.  
  668. int Sys_FileWrite (int handle, void *data, int count)
  669. {
  670.         return write (handle, data, count);
  671. }
  672.  
  673. /*
  674. ================
  675. Sys_MakeCodeWriteable
  676. ================
  677. */
  678. void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
  679. {
  680.         // it's always writeable
  681. }
  682.  
  683.  
  684. /*
  685. ================
  686. Sys_FloatTime
  687. ================
  688. */
  689. double Sys_FloatTime (void)
  690. {
  691.     int                         r;
  692.     unsigned            t, tick;
  693.         double                  ft, time;
  694.         static int              sametimecount;
  695.  
  696.         Sys_PushFPCW_SetHigh ();
  697.  
  698. //{static float t = 0; t=t+0.05; return t;}     // DEBUG
  699.  
  700.     t = *(unsigned short*)real2ptr(0x46c) * 65536;
  701.  
  702.     dos_outportb(0x43, 0); // latch time
  703.     r = dos_inportb(0x40);
  704.     r |= dos_inportb(0x40) << 8;
  705.     r = (r-1) & 0xffff;
  706.  
  707.     tick = *(unsigned short*)real2ptr(0x46c) * 65536;
  708.     if ((tick != t) && (r & 0x8000))
  709.                 t = tick;
  710.  
  711.         ft = (double) (t+(65536-r)) / 1193200.0;
  712.         time = ft - oldtime;
  713.         oldtime = ft;
  714.  
  715.         if (time < 0)
  716.         {
  717.                 if (time > -3000.0)
  718.                         time = 0.0;
  719.                 else
  720.                         time += 3600.0;
  721.         }
  722.  
  723.         curtime += time;
  724.  
  725.         if (curtime == lastcurtime)
  726.         {
  727.                 sametimecount++;
  728.  
  729.                 if (sametimecount > 100000)
  730.                 {
  731.                         curtime += 1.0;
  732.                         sametimecount = 0;
  733.                 }
  734.         }
  735.         else
  736.         {
  737.                 sametimecount = 0;
  738.         }
  739.  
  740.         lastcurtime = curtime;
  741.  
  742.         Sys_PopFPCW ();
  743.  
  744.     return curtime;
  745. }
  746.  
  747.  
  748. /*
  749. ================
  750. Sys_InitFloatTime
  751. ================
  752. */
  753. void Sys_InitFloatTime (void)
  754. {
  755.         int             j;
  756.  
  757.         Sys_FloatTime ();
  758.  
  759.         oldtime = curtime;
  760.  
  761.         j = COM_CheckParm("-starttime");
  762.  
  763.         if (j)
  764.         {
  765.                 curtime = (double) (Q_atof(com_argv[j+1]));
  766.         }
  767.         else
  768.         {
  769.                 curtime = 0.0;
  770.         }
  771.         lastcurtime = curtime;
  772. }
  773.  
  774.  
  775. /*
  776. ================
  777. Sys_GetMemory
  778. ================
  779. */
  780. void Sys_GetMemory(void)
  781. {
  782.         int             j, tsize;
  783.  
  784.         j = COM_CheckParm("-mem");
  785.         if (j)
  786.         {
  787.                 quakeparms.memsize = (int) (Q_atof(com_argv[j+1]) * 1024 * 1024);
  788.                 quakeparms.membase = malloc (quakeparms.memsize);
  789.         }
  790.         else
  791.         {
  792.                 quakeparms.membase = dos_getmaxlockedmem (&quakeparms.memsize);
  793.         }
  794.  
  795.         fprintf(stderr, "malloc'd: %d\n", quakeparms.memsize);
  796.  
  797.         if (COM_CheckParm ("-heapsize"))
  798.         {
  799.                 tsize = Q_atoi (com_argv[COM_CheckParm("-heapsize") + 1]) * 1024;
  800.  
  801.                 if (tsize < quakeparms.memsize)
  802.                         quakeparms.memsize = tsize;
  803.         }
  804. }
  805.  
  806.  
  807. /*
  808. ================
  809. Sys_PageInProgram
  810.  
  811. walks the text, data, and bss to make sure it's all paged in so that the
  812. actual physical memory detected by Sys_GetMemory is correct.
  813. ================
  814. */
  815. void Sys_PageInProgram(void)
  816. {
  817.         int             i, j;
  818.  
  819.         end_of_memory = (int)sbrk(0);
  820.  
  821.         if (lockmem)
  822.         {
  823.                 if (dos_lockmem ((void *)&start_of_memory,
  824.                                                  end_of_memory - (int)&start_of_memory))
  825.                         Sys_Error ("Couldn't lock text and data");
  826.         }
  827.  
  828.         if (lockunlockmem)
  829.         {
  830.                 dos_unlockmem((void *)&start_of_memory,
  831.                                                  end_of_memory - (int)&start_of_memory);
  832.                 printf ("Locked and unlocked %d Mb image\n",
  833.                                 (end_of_memory - (int)&start_of_memory) / 0x100000);
  834.         }
  835.         else if (lockmem)
  836.         {
  837.                 printf ("Locked %d Mb image\n",
  838.                                 (end_of_memory - (int)&start_of_memory) / 0x100000);
  839.         }
  840.         else
  841.         {
  842.                 printf ("Loaded %d Mb image\n",
  843.                                 (end_of_memory - (int)&start_of_memory) / 0x100000);
  844.         }
  845.  
  846. // touch the entire image, doing the 16-page skip so Win95 doesn't think we're
  847. // trying to page ourselves in
  848.         for (j=0 ; j<4 ; j++)
  849.         {
  850.                 for(i=(int)&start_of_memory ; i<(end_of_memory - 16 * 0x1000) ; i += 4)
  851.                 {
  852.                         sys_checksum += *(int *)i;
  853.                         sys_checksum += *(int *)(i + 16 * 0x1000);
  854.                 }
  855.         }
  856. }
  857.  
  858.  
  859. /*
  860. ================
  861. Sys_NoFPUExceptionHandler
  862. ================
  863. */
  864. void Sys_NoFPUExceptionHandler(int whatever)
  865. {
  866.         printf ("\nError: Quake requires a floating-point processor\n");
  867.         exit (0);
  868. }
  869.  
  870.  
  871. /*
  872. ================
  873. Sys_DefaultExceptionHandler
  874. ================
  875. */
  876. void Sys_DefaultExceptionHandler(int whatever)
  877. {
  878. }
  879.  
  880.  
  881. /*
  882. ================
  883. main
  884. ================
  885. */
  886. int main (int c, char **v)
  887. {
  888.         double                  time, oldtime, newtime;
  889.         extern void (*dos_error_func)(char *, ...);
  890.         static  char    cwd[1024];
  891.  
  892.         printf ("Quake v%4.2f\n", VERSION);
  893.        
  894. // make sure there's an FPU
  895.         signal(SIGNOFP, Sys_NoFPUExceptionHandler);
  896.         signal(SIGABRT, Sys_DefaultExceptionHandler);
  897.         signal(SIGALRM, Sys_DefaultExceptionHandler);
  898.         signal(SIGKILL, Sys_DefaultExceptionHandler);
  899.         signal(SIGQUIT, Sys_DefaultExceptionHandler);
  900.         signal(SIGINT, Sys_DefaultExceptionHandler);
  901.  
  902.         if (fptest_temp >= 0.0)
  903.                 fptest_temp += 0.1;
  904.  
  905.         COM_InitArgv (c, v);
  906.  
  907.         quakeparms.argc = com_argc;
  908.         quakeparms.argv = com_argv;
  909.  
  910.         dos_error_func = Sys_Error;
  911.  
  912.         Sys_DetectWin95 ();
  913.         Sys_PageInProgram ();
  914.         Sys_GetMemory ();
  915.  
  916.         atexit (Sys_AtExit);    // in case we crash
  917.  
  918.         getwd (cwd);
  919.         if (cwd[Q_strlen(cwd)-1] == '/') cwd[Q_strlen(cwd)-1] = 0;
  920.         quakeparms.basedir = cwd; //"f:/quake";
  921.  
  922.         isDedicated = (COM_CheckParm ("-dedicated") != 0);
  923.  
  924.         Sys_Init ();
  925.  
  926.         if (!isDedicated)
  927.                 dos_registerintr(9, TrapKey);
  928.  
  929. //Sys_InitStackCheck ();
  930.        
  931.         Host_Init(&quakeparms);
  932.  
  933. //Sys_StackCheck ();
  934.  
  935. //Con_Printf ("Top of stack: 0x%x\n", &time);
  936.         oldtime = Sys_FloatTime ();
  937.         while (1)
  938.         {
  939.                 newtime = Sys_FloatTime ();
  940.                 time = newtime - oldtime;
  941.  
  942.                 if (cls.state == ca_dedicated && (time<sys_ticrate.value))
  943.                         continue;
  944.  
  945.                 Host_Frame (time);
  946.  
  947. //Sys_StackCheck ();
  948.  
  949.                 oldtime = newtime;
  950.         }
  951. }
  952.  
  953.  
  954.