home *** CD-ROM | disk | FTP | other *** search
/ DOS/V Power Report 1998 February / VPR9802A.ISO / BENCH / pfm68621 / PFM686.C next >
C/C++ Source or Header  |  1997-10-06  |  27KB  |  1,167 lines

  1. /*  pfmdpmi ver 2.1A DysanKeihin & (koji) at fext */
  2. /*                                hgg02424@niftyserve.or.jp    */
  3.  
  4.  
  5. #include <stdio.h>
  6. #include <dos.h>
  7. #include <dpmi.h>
  8. #include <stdlib.h>
  9. #include <math.h>
  10.  
  11.  
  12.  
  13.  
  14. /*
  15. #define PRINT_IMED
  16. #define DEBUG 
  17. */
  18.  
  19.  
  20. union REGS inregs,outregs;
  21.  
  22. #define cli asm volatile("cli");
  23. #define sti asm volatile("sti");
  24.  
  25.  
  26. #define TickSet RDTSC(TickStart)
  27. #define TickGet RDTSC(TickStop)
  28.  
  29.  
  30.  
  31. void EvaluateEcacheSize(long Sel, long Offset, long EcacheSize, long FillSize, double Freq);
  32.  
  33.  
  34.  
  35.  
  36. void exagoge(char e_level,char *err_mes1,char *err_mes2)
  37. {
  38.   if (*err_mes2 == (char)NULL) fprintf(stderr,"%s \n",err_mes1);
  39.   else fprintf(stderr,"%s [%s]\n",err_mes1,err_mes2);
  40.   exit(e_level);
  41. }
  42.  
  43.  
  44.  
  45.  
  46.  
  47.  
  48. /* ============  Detect CPUID  ==============   */
  49.  
  50.  
  51. #define cpuid(i_eax,r_eax,r_ebx,r_ecx,r_edx)\
  52.   asm volatile\
  53.   ("\
  54.      movl %4,%%eax
  55.      .byte 0x0f
  56.      .byte 0xa2
  57.      movl %%eax,%0
  58.      movl %%ebx,%1
  59.      movl %%ecx,%2
  60.      movl %%edx,%3
  61.    ":"=g"(r_eax),"=g"(r_ebx),"=g"(r_ecx),"=g"(r_edx)\
  62.     :"g"(i_eax)\
  63.     :"ax","bx","cx","dx"\
  64.   )
  65.  
  66.  
  67. #define MMXFLAG 0x00800000  /* Bit 23*/
  68.  
  69. char flag_p5=0;
  70.  
  71.  
  72. long GetCPUID(char *id_string)
  73. { volatile unsigned long i_eax,r_eax,r_edx;
  74.   volatile unsigned long string_reg[4];
  75.   char VendorString[32], p5_bug_string[64],cputype[7],cpu[4];
  76.   long i,j;
  77.   volatile double c;
  78.  
  79.   asm volatile /* Whether the CPU has ID string */
  80.   ("
  81.      pushfl
  82.      pushfl
  83.      popl  %%eax
  84.      orl  $0x200000,%%eax
  85.      pushl %%eax
  86.      popfl
  87.      pushfl
  88.      popl  %%eax
  89.      popfl
  90.      movl  %%eax,%0
  91.    ":"=g"(r_eax)
  92.     :
  93.     :"ax"
  94.   );
  95.  
  96. #ifdef DEBUG
  97. fprintf(stderr,"%lx \n",r_eax);
  98. #endif
  99.  
  100.   if (!(r_eax & 0x200000))  /* if bit21==1 then P5,P6...*/
  101.   { *id_string = (char)NULL;
  102. #ifdef DEBUG
  103.   printf(" It doesen't have CPUID. \n");
  104. #endif
  105.     return(0);
  106.   }
  107.  
  108. #ifdef DEBUG
  109.   printf(" It has CPUID. \n");
  110. #endif
  111.  
  112.   VendorString[0] = (char)NULL;
  113.   i_eax=0;
  114.   cpuid(i_eax,string_reg[3],string_reg[0],string_reg[2],string_reg[1]);
  115.   for(i=0; i<3; i++)
  116.     for(j=0; j<4; j++)
  117.       VendorString[i*4+j] = (char)( 0xff & (string_reg[i] >> j*8) );
  118.   VendorString[12] = (char)NULL;
  119.  
  120.   i_eax=1;
  121.   cpuid(i_eax,r_eax,string_reg[0],string_reg[2],string_reg[1]);
  122.  
  123.   sprintf(cputype," ??? ");
  124.   if ((r_eax & 0x0ff0) == 0x0000 ) sprintf(cputype,"  non ");
  125.   if ((r_eax & 0x0ff0) == 0x0400 ) sprintf(cputype," 486DX");
  126.   if ((r_eax & 0x0ff0) == 0x0410 ) sprintf(cputype," 486DX");
  127.   if ((r_eax & 0x0ff0) == 0x0420 ) sprintf(cputype," 486SX");
  128.   if ((r_eax & 0x0ff0) == 0x0430 ) sprintf(cputype,"486DX2");
  129.   if ((r_eax & 0x0ff0) == 0x0440 ) sprintf(cputype," 486SL");
  130.   if ((r_eax & 0x0ff0) == 0x0450 ) sprintf(cputype,"486SX2");
  131.   if ((r_eax & 0x0ff0) == 0x0470 ) sprintf(cputype,"WBEDX2");
  132.   if ((r_eax & 0x0ff0) == 0x0480 ) sprintf(cputype,"  DX4 ");
  133.   if ((r_eax & 0x0ff0) == 0x0420 ) sprintf(cputype,"  UMC ");
  134.   if ((r_eax & 0x0ff0) == 0x0510 ) { sprintf(cputype,"  P5  "); flag_p5 = 1; }
  135.   if ((r_eax & 0x0ff0) == 0x0520 ) { sprintf(cputype," P54C "); flag_p5 = 1; }
  136.   if ((r_eax & 0x0ff0) == 0x0530 ) { sprintf(cputype," P24T "); flag_p5 = 1; }
  137.   if ((r_eax & 0x0ff0) == 0x0540 ) sprintf(cputype," P55C ");
  138.   if ((r_eax & 0x0ff0) == 0x0570 ) { sprintf(cputype,"P5note"); flag_p5 = 1; }
  139.   if ((r_eax & 0x0ff0) == 0x04e0 ) sprintf(cputype,"Am5x86");
  140.   if ((r_eax & 0x0ff0) == 0x0610 ) sprintf(cputype,"  P6  ");
  141.   if ((r_eax & 0x0ff0) == 0x0630 ) sprintf(cputype,"Pen-II");
  142.   if ((r_eax & 0x0ff0) == 0x0560 ) sprintf(cputype,"AMD K6");
  143.  
  144.   sprintf(p5_bug_string,"\0");
  145.   if( flag_p5 )
  146.   { c = 824633702449.0;
  147.     if( fabs (1.0 - (1.0/c)*c) > 0.00000000000001 )
  148.       sprintf(p5_bug_string,"\n| This FPU is BUGGY version.             |");
  149.   }
  150.  
  151.   i_eax=1;
  152.   cpuid(i_eax,r_eax,string_reg[0],string_reg[2],r_edx);
  153.  
  154.   if ( MMXFLAG & r_edx) sprintf(cpu,"MMX");
  155.   else sprintf(cpu,"CPU");
  156.  
  157.   sprintf(id_string,"|%s:%6s[%12s Fam%1ld Mdl%1ld Stp%2ld]|%s\0",cpu,
  158.                     cputype,VendorString,0x0f&(r_eax>>8),0x0f&(r_eax>>4),0x0f&r_eax,p5_bug_string );
  159.  
  160.   return(1);
  161. }
  162.  
  163.  
  164.  
  165.  
  166.  
  167.  
  168.  
  169.  
  170.  
  171.  
  172.  
  173. /* ============  Measure Frequency ==============   */
  174.  
  175.  
  176. static unsigned long TickStart, TickStop, Tick;
  177.  
  178.  
  179.  
  180.  
  181.  
  182. #define IOtickGet(counter_l)\
  183.   asm volatile\
  184.   ("\
  185.      movb $0x00,%%al\n\
  186.      outb %%al,$0x43\n\
  187.      inb $0x40,%%al\n\
  188.      xchgb %%al,%%ah\n\
  189.      inb $0x40,%%al\n\
  190.      xchgb %%al,%%ah\n\
  191.      movw %%ax,%0\n\
  192.    ":"=g"(counter_l)\
  193.     :\
  194.     :"ax"\
  195.   )
  196.  
  197.  
  198. #define IOtickRecover\
  199.   asm volatile\
  200.   ("\
  201.      movb $0x36,%%al      /*timer0(system)*/\n\
  202.      outb %%al,$0x43\n\
  203.      xorw %%ax,%%ax\n\
  204.      outb %%al,$0x40\n\
  205.      outb %%al,$0x40\n\
  206.    ":\
  207.     :\
  208.     :"ax"\
  209.   )
  210.  
  211.  
  212.  
  213.  
  214. #define RDTSC(CounterLo)\
  215.   asm volatile\
  216.   ("\
  217.      .byte 0x0f\n\
  218.      .byte 0x31\n\
  219.      movl %%eax,%0\n\
  220.    ":"=g"(CounterLo)\
  221.     :\
  222.     :"ax","dx"\
  223.   )
  224.  
  225.  
  226.  
  227. long ExactTick()
  228. {
  229.   if (TickStop > TickStart) Tick = TickStop-TickStart;
  230.   else Tick = TickStop + (unsigned long)(~TickStart) + 1;
  231.   return(Tick);
  232. }
  233.  
  234.  
  235.  
  236.  
  237. #define CMOS_ADDR   0x70
  238. #define CMOS_SEC    0x00
  239. #define CMOS_DATA   0x71
  240.  
  241. #define COUNTER 2386360 /* Hz */
  242.  
  243. double GetFrequency(void)
  244. {
  245.   unsigned long Diff;
  246.   unsigned short NewCounter,PreviousCounter;
  247.   int j;
  248.   unsigned char sec,sec1;
  249.   long CounterValSec, Vcount;
  250.   double CycleTime;
  251.   unsigned long DelayRDTSC;
  252.  
  253.   for(j=0; j<2; j++)
  254.   {
  255.     TickSet;
  256.     TickGet;
  257.   }
  258.   if (TickStart == TickStop ) 
  259.     exagoge(1," Sorry, this CPU doesn't have RDTSC instruction.\n Use PFM586 or PFM486.","");
  260.  
  261.   DelayRDTSC = ExactTick();
  262.   IOtickRecover;
  263.  
  264.   IOtickGet(PreviousCounter);  /* wait for tick*/
  265.   while(1)
  266.   { IOtickGet(NewCounter);
  267.     if ( NewCounter > PreviousCounter) break;
  268.     PreviousCounter = NewCounter;
  269.   }
  270.  
  271.  
  272.   for(j=0; j<2; j++)
  273.   {
  274.     TickSet;
  275.  
  276.     { int i=0;                  /* wait for 10 ticks*/
  277.       while(i<10)
  278.       { IOtickGet(PreviousCounter);
  279.         while(1)
  280.         { IOtickGet(NewCounter);
  281.           if ( NewCounter > PreviousCounter) break;
  282.           PreviousCounter = NewCounter;
  283.         }
  284.         i++;
  285.       }
  286.     }
  287.  
  288.     TickGet;
  289.   }
  290.   
  291.   Diff = ExactTick()-DelayRDTSC;
  292.  
  293.  
  294. #ifdef DEBUG
  295. printf("Delay:%lx\n",DelayRDTSC);
  296. printf("Diff :%lx\n",Diff);
  297. #endif
  298.  
  299. /* Check CMOS clock */
  300.   
  301.   outportb(CMOS_ADDR, CMOS_SEC);
  302.   sec = inportb(CMOS_DATA);
  303.  
  304.   Vcount = 0;
  305.   while(1)
  306.   { outportb(CMOS_ADDR, CMOS_SEC);
  307.     if ((sec1 = inportb(CMOS_DATA)) == sec) { if ( 10000 == Vcount++) break; }
  308.     else Vcount = 0;
  309.     sec = sec1;
  310.   }
  311.   while(1)
  312.   { outportb(CMOS_ADDR, CMOS_SEC);
  313.     if (sec != inportb(CMOS_DATA))  break;
  314.   }
  315.   
  316.  
  317.   TickSet;
  318.  
  319.   Vcount = 0;
  320.   while(1)
  321.   { outportb(CMOS_ADDR, CMOS_SEC);
  322.     if ( (sec1 = inportb(CMOS_DATA))==sec ) { if ( 10000 == Vcount++) break; }
  323.     else Vcount = 0;
  324.     sec = sec1;
  325.   }
  326.   while(1)
  327.   { outportb(CMOS_ADDR, CMOS_SEC);
  328.     if (sec != inportb(CMOS_DATA))  break;
  329.   }
  330.   TickGet;
  331.  
  332.  
  333.   CounterValSec = ExactTick();
  334.   CycleTime = 1./CounterValSec;
  335.  
  336. #ifdef DEBUG
  337.   fprintf(stdout,"%ld\n",CounterValSec);
  338.   fprintf(stdout,"%lf\n",COUNTER/(double)(10*0x10000)*(double)Diff);
  339. #endif
  340.   if (abs ( (double)CounterValSec/1000000. - COUNTER/(double)(10*0x10000)*(double)Diff/1000000) > 0.1 )
  341.   { fprintf(stdout,"-------------------------------------------------\n");
  342.     fprintf(stdout,"Either CMOS-RTC or 14.318MHz clock seems strange.\n");
  343.     fprintf(stdout,"factor : :%5.4f\n",CounterValSec/(COUNTER/(double)(10*0x10000)*(double)Diff));
  344.   }
  345.  
  346.   return (.000001/CycleTime);
  347.  
  348. }
  349.  
  350.  
  351.  
  352.  
  353.  
  354.  
  355.  
  356. /* ============  Memory Setup ==============   */
  357.  
  358.  
  359. #define SegAttrConfExecutable 0x9a
  360. #define SegAttrDataRW 0x92
  361.  
  362.  
  363. long SegAttributeSet(long Sel,unsigned char Attr)
  364. { long PrevAttr, s;
  365.   unsigned char _buffer[8];
  366.   long i;
  367.   long CPL;
  368.  
  369.   CPL = _my_cs() & 0x03;
  370.   Attr |= ( CPL << 5 );
  371.  
  372.   s = __dpmi_get_descriptor(Sel, _buffer); /* DPMI 0.9 AX=000b */
  373.  
  374. #ifdef DEBUG
  375. printf("s:%lx \n",s);
  376. for (i=0; i<8; i++)
  377.   printf("%2x ",_buffer[7-i]);
  378. printf("\n");
  379. #endif
  380.  
  381.   PrevAttr = _buffer[5];
  382.   _buffer[5] = Attr;
  383.   _buffer[6] |= 0x40; /* default size : 32bit */
  384.   s = __dpmi_set_descriptor(Sel, _buffer);  /* DPMI 0.9 AX=000c */
  385.  
  386. #ifdef DEBUG
  387. printf("s:%lx \n",s);
  388. s = __dpmi_get_descriptor(Sel, _buffer); /* DPMI 0.9 AX=000b */
  389. printf("s:%lx \n",s);
  390. for (i=0; i<8; i++)
  391.   printf("%2x ",_buffer[7-i]);
  392. printf("\n");
  393. #endif
  394.  
  395.   return(PrevAttr);
  396.  
  397. }
  398.  
  399.  
  400.  
  401.  
  402. long AllocatePhysicalMem(long PhyAddr, long Size)
  403. { long Sel,LAddr,base;
  404.   __dpmi_meminfo info;
  405.   long s,i;
  406.  
  407.   Sel= __dpmi_allocate_ldt_descriptors(1);
  408. #ifdef DEBUG
  409.   printf("PhyMemSel: %x \n",Sel);
  410. #endif
  411.  
  412.   info.handle = 0;
  413.   info.size = Size;
  414.   info.address = PhyAddr;
  415.  
  416.   s = __dpmi_physical_address_mapping(&info);
  417.   if ( s ) exagoge(-1,"Memory allocation Failure","DPMI(0800)");
  418.   LAddr = info.address;
  419. #ifdef DEBUG
  420.   printf("LAddr  :%lp \n",info.address);
  421. #endif
  422.  
  423.   s = __dpmi_lock_linear_region(&info);             /* DPMI 0.9 AX=0600 */
  424. #ifdef 0
  425.   if ( s ) 
  426.   { fprintf(stderr,"Lock Error : %lx -- %lx\n",PhyAddr,PhyAddr+Size);
  427.     exagoge(-1,"Memory allocation Failure","DPMI(0600)");
  428.   }
  429. #endif
  430. #ifdef DEBUG
  431.   printf("s:%lx[__dpmi_lock_linear_region] \n",s);
  432.   printf("handle:%lx \n",info.handle);
  433.   printf("size  :%lx \n",info.size);
  434.   printf("addr  :%lp \n",info.address);
  435. #endif
  436.  
  437.   s = __dpmi_set_segment_base_address(Sel,LAddr);        /* DPMI 0.9 AX=0007 */
  438.   if ( s ) exagoge(-1,"Memory allocation Failure","DPMI(0007)");
  439.  
  440.   s = __dpmi_set_segment_limit(Sel, Size|0xfff);         /* DPMI 0.9 AX=0008 */
  441.   if ( s ) exagoge(-1,"Memory allocation Failure","DPMI(0008)");
  442.  
  443. #ifdef DEBUG
  444.   __dpmi_get_segment_base_address(Sel, &base);
  445.   printf("Selector 0x%04x : base=0x%lx, limit=0x%lx, flags=0x%x\n",
  446.   Sel, base, __dpmi_get_segment_limit(Sel),
  447.   __dpmi_get_descriptor_access_rights(Sel));
  448. #endif
  449.  
  450.   for(i=0; i<Size; i+=256)
  451.     _farpokel(Sel,i,0);
  452.  
  453.   _farpokel(Sel,0,0xAA);
  454.   _farpokel(Sel,Size-1,0xAA);
  455.   if((_farpeekb(Sel,0) != 0xAA) || (_farpeekb(Sel,Size - 1) != 0xAA) )
  456.   {
  457.     fprintf(stdout,"Requested range : %08lX - %08lX \n",PhyAddr,PhyAddr+Size);
  458.     exagoge(1,"Memory out of range.","");
  459.   }
  460.  
  461.  
  462.   return(Sel);
  463. }
  464.  
  465.  
  466.  
  467.  
  468. long AllocateMemBlock( long Size)
  469. { long Sel,LAddr,base;
  470.   __dpmi_meminfo info;
  471.   long s=0,i;
  472.  
  473.   Sel= __dpmi_allocate_ldt_descriptors(1);
  474. #ifdef DEBUG
  475.   printf("MemBlockSel: %x \n",Sel);
  476. #endif
  477.  
  478.   info.handle = 0;
  479.   info.size = Size;
  480.   info.address = 0;
  481.  
  482.   s = __dpmi_allocate_memory(&info); /* DPMI 0.9 AX=0501 */
  483.   if ( s ) exagoge(-1,"Memory allocation Failure","DPMI(0501)");
  484.   LAddr = info.address;
  485. #ifdef DEBUG
  486.   printf("LAddr  :%lp \n",info.address);
  487. #endif
  488.  
  489.  
  490.   s = __dpmi_lock_linear_region(&info);               /* DPMI 0.9 AX=0600 */
  491.   if ( s ) exagoge(-1,"Memory allocation Failure","DPMI(0600)");
  492.  
  493. #ifdef DEBUG
  494.   printf("s:%lx[__dpmi_lock_linear_region] \n",s);
  495.   printf("handle:%lx \n",info.handle);
  496.   printf("size  :%lx \n",info.size);
  497.   printf("addr  :%lp \n",info.address);
  498. #endif
  499.  
  500.   s = __dpmi_set_segment_base_address(Sel,LAddr);     /* DPMI 0.9 AX=0007 */
  501.   if ( s ) exagoge(-1,"Memory allocation Failure","DPMI(0007)");
  502.  
  503.   s = __dpmi_set_segment_limit(Sel, Size | 0xfff);       /* DPMI 0.9 AX=0008 */
  504.   if ( s ) exagoge(-1,"Memory allocation Failure","DPMI(0008)");
  505.  
  506. #ifdef DEBUG
  507.   __dpmi_get_segment_base_address(Sel, &base);
  508.   printf("Selector 0x%04x : base=0x%lx, limit=0x%lx, flags=0x%x\n",
  509.   Sel, base, __dpmi_get_segment_limit(Sel),
  510.   __dpmi_get_descriptor_access_rights(Sel));
  511. #endif
  512.  
  513.   for(i=0; i<Size; i+=256)
  514.     _farpokel(Sel,i,0);
  515.  
  516.   return(Sel);
  517. }
  518.  
  519.  
  520.  
  521.  
  522.  
  523.  
  524.  
  525.  
  526. /* ============  Cache, Main Read ==============   */
  527.  
  528.  
  529. #define fp4(val4) fp((val4 & 0xff)); fp(((val4 >> 8) & 0xff)); fp(((val4 >> 16) & 0xff)); fp(((val4 >> 24) & 0xff));
  530. #define fp(val)  { _farpokeb(Sel, pp + Offset, val); pp++; }
  531.  
  532. long FillTestCode(long Sel, long Offset, long EcacheSize, long FillSize )
  533. { long ReadBlock, i, pp=0, BigLoopStartPoint, FillStartPoint;
  534.  
  535.   ReadBlock = EcacheSize / (24 / 4);
  536.  
  537.   FillStartPoint = Offset + EcacheSize * 4;
  538. #ifdef 0
  539. printf("Offset          : %lx \n",Offset);
  540. printf("EcacheSize      : %lx \n",EcacheSize);
  541. printf("FillStartPoint  : %lx \n",FillStartPoint);
  542. printf("FillSize        : %lx \n",FillSize);
  543. printf("\n");
  544. #endif
  545.   SegAttributeSet(Sel,SegAttrDataRW);
  546.  
  547.   fp(0x1e);    /*  push %%ds  */
  548.  
  549.   fp(0x66); fp(0x8c); fp(0xc9);     /* movw %%cs,%%cx */
  550.   fp(0x66); fp(0x8e); fp(0xd9);     /* movw %%cx,%%ds */
  551.  
  552.   fp(0xbf); fp4(0x04);              /* movl $04,edi */
  553.  
  554.   BigLoopStartPoint = pp + Offset;
  555.  
  556.   if (FillSize != 0) /* for main */
  557.   { 
  558.     for (i=0; i<FillSize*4; i++)
  559.       fp(0x90);   /* nop */
  560.   }
  561.  
  562.  
  563.   while(1) /* auto aline */
  564.   {
  565.     if ( ( pp % 4 ) == 0 ) break;
  566.       fp(0x90); /* nop */
  567.   }
  568.   
  569.   fp(0x0f); fp(0x31);   /* RDTSC  */
  570.   fp(0x89); fp(0xc6);   /* movl eax,esi    */
  571.   for(i=0; i<ReadBlock; i++)
  572.   {
  573.     fp(0x81); fp(0xc3); fp4(0x00); /* 81c300000000  adc eax,0x0    */
  574.     fp(0x81); fp(0xc0); fp4(0x00); /* 81c000000000  adc ebx,0x0    */
  575.     fp(0x81); fp(0xc1); fp4(0x00); /* 81c100000000  adc ecx,0x0    */
  576.     fp(0x81); fp(0xc2); fp4(0x00); /* 81c200000000  adc edx,0x0    */
  577.   }
  578.  
  579.   fp(0x0f); fp(0x31);  /* RDTSC  */
  580.   fp(0x29); fp(0xf0);  /* subl %%esi,%%eax  :  eax - esi => eax */
  581.  
  582.   fp(0x4f);  /* dec %%edi */
  583.   
  584.   fp(0x74); fp(0x07);    /* jz +07 */
  585.  
  586.   fp(0xb8);  /* mov *BigLoopStart,%%eax */
  587.   fp4( BigLoopStartPoint );
  588.  
  589.   fp(0xff); fp(0xe0);    /* jmp %%eax */
  590.  
  591.   fp(0x1f);  /*  pop %%ds  */
  592.  
  593.   fp(0xcb);  /* far ret immediate */
  594.  
  595.   return(ReadBlock);
  596. }
  597.  
  598.  
  599.  
  600.  
  601. long CallTestCode(long Sel, long Offset)
  602. {
  603.   long Count;
  604.   struct
  605.   {
  606.     unsigned long Offset;
  607.     unsigned long Selector;
  608.   }JumpAdd;
  609.  
  610.   SegAttributeSet(Sel,SegAttrConfExecutable);
  611.  
  612.   JumpAdd.Selector = Sel;
  613.   JumpAdd.Offset = Offset;
  614.  
  615.   asm volatile
  616.   ("\
  617.      movl %1,%%eax
  618.      lcall (%%eax)
  619.      movl %%eax,%0
  620.      ":"=g"(Count)\
  621.       :"g"(&JumpAdd)\
  622.       :"eax");
  623.  
  624.   return(Count);
  625.  
  626. }
  627.  
  628.  
  629.  
  630.  
  631.  
  632. double EcacheRead(long Sel, long Offset, long EcacheSize, double Freq)
  633. {
  634.   long CounterValER, ReadBlockER;
  635.   double TimeER;
  636.   long Count;
  637.   ReadBlockER = FillTestCode(Sel, Offset, EcacheSize, 0 );
  638.  
  639.  
  640.   Count = CallTestCode(Sel, Offset);
  641.   CounterValER = Count;
  642.  
  643. #ifdef DEBUG
  644. fprintf(stdout,"CounterValER:%ld \n",CounterValER);
  645. #endif
  646.  
  647. /* call overhead of E-cache read */
  648.  
  649.   FillTestCode(Sel, Offset, 0, 0 );
  650.  
  651.   Count = CallTestCode(Sel, Offset);
  652.   CounterValER -= Count;
  653.  
  654. #ifdef DEBUG
  655. fprintf(stdout,"CounterValER:%ld  %ld\n",CounterValER,Count);
  656. #endif
  657.  
  658.   TimeER = (double)(CounterValER)/(double)(ReadBlockER * 24 / 4 * Freq) * 1000.;
  659.  
  660. #ifdef PRINT_IMED
  661.   fprintf(stdout,"CounterValER:%ld \n",CounterValER);
  662.   fprintf(stdout,"E-cache read  %6.2f[ns/dword] :%5.2f[clocks]\n",TimeER,TimeER/(1000./Freq));
  663. #endif
  664.  
  665.   return (TimeER);
  666.  
  667. }
  668.  
  669.  
  670.  
  671. double MainRead(long Sel, long Offset, long EcacheSize, long FillSize, double Freq)
  672. {
  673.   long CounterValMR, ReadBlockMR;
  674.   double TimeMR;
  675.   long Count;
  676.  
  677.   ReadBlockMR = FillTestCode(Sel, Offset, EcacheSize, FillSize );
  678.  
  679.   Count = CallTestCode(Sel, Offset);
  680.   CounterValMR = Count;
  681.  
  682. #ifdef DEBUG
  683. fprintf(stdout,"CounterValMR:%ld \n",CounterValMR);
  684. #endif
  685.  
  686. /* call overhead of E-cache read */
  687.  
  688.   FillTestCode(Sel, Offset, 0, 0 );
  689.  
  690.   Count = CallTestCode(Sel, Offset);
  691.   CounterValMR -= Count;
  692.  
  693. #ifdef DEBUG
  694. fprintf(stdout,"CounterValMR:%ld  %ld\n",CounterValMR,Count);
  695. #endif
  696.  
  697.   TimeMR = (double)(CounterValMR)/(double)(ReadBlockMR * 24 / 4 * Freq) * 1000.;
  698.  
  699. #ifdef PRINT_IMED
  700.   fprintf(stdout,"CounterValMR:%ld \n",CounterValMR);
  701.   fprintf(stdout,"E-cache read  %6.2f[ns/dword] :%5.2f[clocks]\n",TimeMR,TimeMR/(1000./Freq));
  702. #endif
  703.  
  704.   return (TimeMR);
  705.  
  706. }
  707.  
  708.  
  709.  
  710.  
  711.  
  712.  
  713.  
  714. /* ============  Cache, Main Write ==============   */
  715.  
  716.  
  717.  
  718.  
  719.  
  720. long DoContinuousPush(CodePointer, StackSel )
  721. { long Count;
  722.   
  723.   SegAttributeSet(StackSel,SegAttrDataRW);
  724.   
  725.   asm volatile
  726.   ("
  727.      movl  %1,%%ebx
  728.      movl  %2,%%eax
  729.      call  %%ebx
  730.      movl  %%eax,%0
  731.    ":"=g"(Count)
  732.     :"g"(CodePointer),"g"(StackSel)
  733.     :"ax","bx","dx"
  734.   );
  735.  
  736.   return(Count);
  737.  
  738. }
  739.  
  740.  
  741.  
  742.  
  743.  
  744.  
  745.  
  746. #ifdef fp
  747.   #undef fp
  748. #endif
  749. #define fp(val)  { *pp++ = val; }
  750.  
  751.  
  752.  
  753. void SetCodeContinuousPush(char *CodePointer, long StackStartPoint, long PushUnit, long PushLoops, long FillSize)
  754. { long i;
  755.   unsigned char *pp;
  756.   long EcacheSize_ , BigLoopStart, FillStartPoint;
  757.  
  758.   EcacheSize_ = PushLoops * PushUnit * 8;
  759.  
  760.   pp = CodePointer;
  761.  
  762.   FillStartPoint = StackStartPoint;
  763.  
  764. #ifdef DEBUG
  765. printf("StackStartPoint : %lx \n",StackStartPoint);
  766. printf("EcacheSize_     : %lx \n",EcacheSize_);
  767. printf("FillStartPoint  : %lx \n",FillStartPoint);
  768. printf("FillSize        : %lx \n",FillSize);
  769. printf("\n");
  770. #endif
  771.  
  772.   fp(0x1e);        /*  push %%ds  */
  773.   fp(0x06);        /*  push %%es  */
  774.   fp(0x55);        /*  push %%ebp  */
  775.  
  776.   fp(0x66); fp(0x8e); fp(0xd0);     /*  movw  %ax,%ss */
  777.   fp(0x66); fp(0x8e); fp(0xc0);     /*  movw  %%ax,%%es */
  778.   fp(0x66); fp(0x8e); fp(0xd8);     /*  movw  %%ax,%%ds */
  779.   fp(0x89); fp(0xe5);               /*  movl  %esp,%ebp */
  780.  
  781.   fp(0xbb); fp4(0x04);  /* movl $04,%%ebx   : 4 Big loops*/
  782.  
  783.   BigLoopStart = (long)pp;
  784.  
  785.   /* Big Loops Start */
  786.   /* load StackStartPoint to esp & edi */
  787.   fp(0xb9);        /*  mov imm32, %%ecx */
  788.   fp4( StackStartPoint );
  789.   fp(0x89); fp(0xcc);        /*  movl  %%ecx,%%esp   StackOffset */
  790.   fp(0x89); fp(0xcf);  /*  movl %%ecx,%%edi  : same as StackOffset pointer */
  791.  
  792.   if( FillSize == 0)
  793.   { /* for cache */
  794.     
  795.     fp(0xb9);        /*  mov imm32, %%ecx*/
  796.     fp4( EcacheSize_ );
  797.     fp(0xfd);        /*  std  */
  798.     fp(0xf3); fp(0xab);        /*  rep stosl  */
  799.     
  800.     fp(0xbe);        /*  mov imm32, %%esi */
  801.     fp4( StackStartPoint );
  802.     fp(0xb9);        /*  mov imm32, %%ecx*/
  803.     fp4( EcacheSize_ );
  804.     fp(0xf3); fp(0xad);        /*  rep lodsl (eax is affected) */
  805.   }
  806.   else
  807.   { /* for Main */
  808.     fp(0xb9);        /*  mov imm32, %%ecx */
  809.     fp4( FillStartPoint );
  810.     fp(0x89); fp(0xcf);        /*  movl  %%ecx,%%edi */
  811.     
  812.     fp(0xb9);        /*  mov imm32, %%ecx*/
  813.     fp4( FillSize );
  814.  
  815.     fp(0xfc);        /*  cld  */
  816.     fp(0xf3); fp(0xab);   /*  rep stosl  */
  817.   }
  818.  
  819.   fp(0xfc);      /*  cld  */
  820.  
  821.   fp(0xb9);        /*  mov imm32, %%ecx */
  822.   fp4( PushLoops );
  823.   
  824.   while(1) /* auto aline */
  825.   {
  826.     if ( ( (long)pp % 4 ) == 0 ) break;
  827.     fp(0x90);         /*  Nop */
  828.   }
  829.  
  830.   fp(0x0f); fp(0x31);     /*  RDTSC  */
  831.   fp(0x89); fp(0xc6);     /*  movl %%eax, %%esi  */
  832.  
  833.   for (i=0; i<PushUnit; i++)
  834.     fp(0x60);  /*  pushal*/
  835.  
  836.   fp(0xe2);    /* loop  0xbe-0xfe = Head of push codes (-0x40) */
  837.   fp(0xfe - PushUnit);
  838.  
  839.   fp(0x0f); fp(0x31);      /*  RDTSC  */
  840.   fp(0x29); fp(0xf0);      /* subl %%esi,%%eax  : eax - esi => eax */
  841.  
  842.   fp(0x4b);        /* dec %%ebx */
  843.  
  844.   fp(0x74); fp(0x07);      /* jz +07 */
  845.  
  846.   fp(0xb9);        /* mov *BigLoopsStart,%%ecx */
  847.   fp4( BigLoopStart );
  848.   fp(0xff); fp(0xe1);   /* jmp %%ecx */
  849.  
  850. /* Recover SS ESP */
  851.   fp(0x66); fp(0xb9);           /*   movw  imm16,%%cx   */
  852.   fp( _my_ss() & 0xff);         /* LSB */
  853.   fp((_my_ss() >> 8) & 0xff);   /*  MSB */
  854.   fp(0x66); fp(0x8e); fp(0xd1); /*   movw  %cx,%ss   */
  855.   fp(0x89); fp(0xec);           /*   movl  %ebp,%esp */
  856.  
  857.   fp(0x5d);        /*  pop %%ebp  */
  858.   fp(0x07);        /*  pop %%es  */
  859.   fp(0x1f);        /*  pop %%ds  */
  860.  
  861.   fp(0xc3); /* ret immediate */
  862.  
  863. }
  864.  
  865.  
  866.  
  867. static unsigned char CodePointer[512];
  868.  
  869.  
  870. #define PushUnit 64
  871.  
  872. double EcacheWrite(long Sel, long Offset, long EcacheSize, double Freq)
  873. {
  874.   long CounterValEW, Count, i;
  875.   double TimeEW;
  876.   long PushLoops, StackStartPoint;
  877.   
  878.   StackStartPoint = Offset + EcacheSize*4;
  879.   PushLoops = EcacheSize/PushUnit/8;
  880.   
  881.  
  882.   SetCodeContinuousPush(CodePointer, StackStartPoint, PushUnit, PushLoops, 0 );
  883.  
  884.   Count = DoContinuousPush(CodePointer, Sel);
  885.   CounterValEW = Count;
  886.  
  887. /* loop & call overhead of E-cache write */
  888.  
  889.   SetCodeContinuousPush(CodePointer, StackStartPoint, 0, PushLoops, 0 );
  890.   Count = DoContinuousPush(CodePointer, Sel);
  891.   CounterValEW -= Count;
  892.  
  893.   TimeEW = ((double)CounterValEW )/(double)(EcacheSize * Freq)*1000. ;
  894. #ifdef PRINT_IMED
  895.   fprintf(stdout,"E-cache write %6.2f[ns/dword] :%5.2f[clocks]\n",TimeEW,TimeEW/(1000./Freq));
  896. #endif
  897.  
  898.   return (TimeEW);
  899.  
  900. }
  901.  
  902.  
  903.  
  904.  
  905.  
  906. #define MinMainSize 512  /* 2k */
  907.  
  908. double MainWrite(long Sel, long Offset, long MainSize, long FillSize, double Freq)
  909. {
  910.   long CounterValMW, Count, i;
  911.   double TimeMW;
  912.   long PushLoops, StackStartPoint;
  913.   
  914.   StackStartPoint = Offset + (MainSize+MinMainSize)*4;
  915.   PushLoops = (MainSize+MinMainSize)/PushUnit/8;
  916.  
  917.  
  918.   SetCodeContinuousPush(CodePointer, StackStartPoint, PushUnit, PushLoops, FillSize);
  919.   
  920.   Count = DoContinuousPush(CodePointer, Sel);
  921.   CounterValMW = Count;
  922.  
  923.  
  924. /* loop & call overhead of E-cache write */
  925.  
  926.   SetCodeContinuousPush(CodePointer, (Offset + MinMainSize*4), PushUnit, 1, FillSize );
  927.   Count = DoContinuousPush(CodePointer, Sel);
  928.  
  929. #ifdef DEBUG
  930. printf("MW %ld : %5.4f \n",CounterValMW,(double)CounterValMW /(double)MainSize);
  931. printf("Count %ld : %5.4f \n",Count,(double)Count /(double)MinMainSize);
  932. #endif
  933.  
  934.   CounterValMW -= Count;
  935.  
  936.  
  937.   TimeMW = ((double)CounterValMW )/(double)(MainSize * Freq)*1000. ;
  938. #ifdef PRINT_IMED
  939.   fprintf(stdout,"E-cache write %6.2f[ns/dword] :%5.2f[clocks]\n",TimeMW,TimeMW/(1000./Freq));
  940. #endif
  941.  
  942.   return (TimeMW);
  943.  
  944. }
  945.  
  946.  
  947.  
  948.  
  949.  
  950.  
  951.  
  952.  
  953.  
  954.  
  955.  
  956.  
  957.  
  958.  
  959.  
  960.  
  961.  
  962.  
  963.  
  964.  
  965.  
  966. void main(int argc,char **argv)
  967. {
  968.   long FillSize,EcacheSize,AllocSize,kbytes;
  969.   char VendorString[128],CacheSizeString[128];
  970.   double TimeER,TimeEW,TimeMR,TimeMW,Freq;
  971.   long Sel, PhyAddr = -1;
  972.  
  973.  
  974.   fprintf(stdout,"\n-- pfm686  ver2.1A  DysanKeihin & (koji) --\n");
  975.  
  976. #ifdef DEBUG
  977. /* dpmi test */
  978.   inregs.x.ax=0x0400;
  979.   int86(0x31,&inregs,&outregs);
  980.   if ((outregs.x.bx & 1) == 0 ){ printf ("No DPMI installed!\n"); exit(1); }
  981.   printf("DPMI test : %lx\n",outregs.x.bx);
  982. #endif
  983.  
  984.  
  985.   CacheSizeString[0] = '\0';
  986.   kbytes = 256;
  987.  
  988.   if (argc != 1)
  989.   { int i;
  990.     for (i=1; i<argc; i++)
  991.     {
  992.       if ( '0' <= argv[i][0] && argv[i][0] <= '9')
  993.       { kbytes = atol(argv[i]);
  994.         if ( (double)kbytes != atof(argv[i]))
  995.           exagoge(-1,"Sorry, cache size must be integer.",argv[i]);
  996.         sprintf(CacheSizeString,"| Cache size : [%4ld]Kbytes              |",kbytes);
  997.       }
  998.       if ( strchr(argv[i],'a') != NULL || strchr(argv[i],'A' ) != NULL)
  999.       { 
  1000.         if( i+1 > argc ) exagoge(-1,"Please define start address.","");
  1001.         sscanf(argv[i+1],"%x",&PhyAddr);
  1002.         i++;
  1003.       }
  1004.     }
  1005.   }
  1006.  
  1007.  
  1008.   if ( kbytes <= 1 )
  1009.   { fprintf(stderr,"Cache size must be more than 2kbytes.\n");
  1010.     kbytes = 2;
  1011.   }
  1012.   
  1013.   if ( kbytes & 1 == 1 )
  1014.   { fprintf(stderr,"Please define cache size with even value.\n");
  1015.     kbytes++;
  1016.   }
  1017.  
  1018. /*  if ( kbytes > 32 ) kbytes -=2;  <-- pfm686 v1.2*/
  1019.   EcacheSize = kbytes*256;/* array size counted by long */
  1020.  
  1021.   if ( EcacheSize < 65500 ) AllocSize = 65500;
  1022.   else AllocSize = EcacheSize;
  1023.  
  1024.  
  1025. /*  FillSize = ( EcacheSize*2 > 1024*256 )? EcacheSize*2:1024*256;     <-- 686 v1.2*/
  1026.   FillSize = AllocSize*2;
  1027.   if (FillSize < 1024*256) FillSize = 2048*256;
  1028.  
  1029.   if ( PhyAddr != -1 ) 
  1030.   { Sel = AllocatePhysicalMem(PhyAddr, (AllocSize + FillSize)*4+1024);
  1031.   }
  1032.   else
  1033.   { Sel = AllocateMemBlock( (AllocSize + FillSize)*4 + 1024);
  1034.   }
  1035.  
  1036.  
  1037.  
  1038. /*  cpuid  */
  1039. #ifdef PRINT_IMED
  1040.   if ( GetCPUID(&VendorString[0]) ) fprintf(stdout,"%s\n",VendorString);
  1041. #endif
  1042.  
  1043.  
  1044.  
  1045. #ifdef DEBUG
  1046.   printf(" cli \n");
  1047. #endif
  1048.  
  1049.   cli;
  1050.  
  1051.  
  1052. /* evaluate clock Frequency */
  1053.  
  1054.   Freq = GetFrequency();
  1055.  
  1056.  
  1057. #ifdef PRINT_IMED
  1058.   fprintf(stdout,"CPU Frequency %6.2f[MHz]\n",Freq);
  1059. #endif
  1060.  
  1061.  
  1062.  
  1063. EvaluateEcacheSize(Sel, 0, EcacheSize, FillSize, Freq);
  1064.  
  1065. /* e-cache read */
  1066. TimeER = EcacheRead(Sel, 0, EcacheSize, Freq);
  1067.  
  1068. /* E-cache write */
  1069. TimeEW = EcacheWrite(Sel, 0, EcacheSize, Freq);
  1070.  
  1071. /* main read */
  1072. TimeMR = MainRead(Sel, 0, EcacheSize , FillSize, Freq);
  1073.  
  1074. /* main write */
  1075. TimeMW = MainWrite(Sel, 0, EcacheSize , FillSize, Freq);
  1076.  
  1077.  
  1078.  
  1079.  
  1080. /* Recover timer IC  */
  1081.   IOtickRecover;
  1082.   sti;
  1083.  
  1084.  
  1085.  
  1086. /*  print   */
  1087.  
  1088.  
  1089. #ifndef PRINT_IMED
  1090.   if ( GetCPUID(&VendorString[0]) )
  1091.   { fprintf(stdout,"------------------------------------------\n");
  1092.     fprintf(stdout,"%s\n",VendorString);
  1093.   }
  1094.  
  1095.   if( PhyAddr != -1 )
  1096.   { fprintf(stdout,"| Cache fill %08lX - %08lX         |\n",PhyAddr,PhyAddr+EcacheSize*4);
  1097.     fprintf(stdout,"| Dummy fill %08lX - %08lX         |\n",PhyAddr+EcacheSize,PhyAddr+(AllocSize+FillSize)*4+1024);
  1098.   }
  1099.  
  1100.  
  1101.   if( CacheSizeString[0] != '\0' )
  1102.     fprintf(stdout,"%s\n",CacheSizeString);
  1103.   fprintf(stdout,"|----------------------------------------|\n");
  1104.   { char st[5][10];
  1105.     sprintf(st[0],"%6.2f",Freq);
  1106.     sprintf(st[1],"%7.3f",TimeER);
  1107.     sprintf(st[2],"%7.3f",TimeEW);
  1108.     sprintf(st[3],"%7.3f",TimeMR);
  1109.     sprintf(st[4],"%7.3f",TimeMW);
  1110.     
  1111.     fprintf(stdout,"|  %6s[MHz]  | [ns/dword] |[CPUclocks]|\n",st[0]);
  1112.     fprintf(stdout,"|---------------+------------+-----------|\n");
  1113.     fprintf(stdout,"| E-cache read  | %8s   |  %6.3f   |\n",st[1],TimeER/(1000./Freq));
  1114.     fprintf(stdout,"| E-cache write | %8s   |  %6.3f   |\n",st[2],TimeEW/(1000./Freq));
  1115.     fprintf(stdout,"| main    read  | %8s   |  %6.3f   |\n",st[3],TimeMR/(1000./Freq));
  1116.     fprintf(stdout,"| main    write | %8s   |  %6.3f   |\n",st[4],TimeMW/(1000./Freq));
  1117.     fprintf(stdout,"------------------------------------------\n");
  1118. /*
  1119.     printf("[%s]",st[0]);
  1120.     printf("[%s]",st[1]);
  1121.     printf("[%s]",st[2]);
  1122.     printf("[%s]",st[3]);
  1123.     printf("[%s]",st[4]);
  1124. */
  1125.   }
  1126.   
  1127. #endif
  1128. }
  1129.  
  1130.  
  1131.  
  1132.  
  1133. #define MaxCacheSize 2048
  1134.  
  1135. void EvaluateEcacheSize(long Sel, long Offset, long EcacheSize, long FillSize, double Freq)
  1136. {
  1137.   long Sizes[32]={2,4,6,8,12,16,24,32,48,64,96,128,192,256,384,512,768,1024,1536,MaxCacheSize};
  1138.   long Counts[32],MaxCacheCount,i,CacheLayer=0, ReadBlockMR;
  1139.   
  1140.   ReadBlockMR = FillTestCode(Sel, Offset, EcacheSize, FillSize );
  1141.   MaxCacheCount = CallTestCode(Sel, Offset);
  1142.  
  1143. #ifdef DEBUG
  1144. printf("MaxCacheCount:%ld\n",MaxCacheCount);
  1145. #endif
  1146.  
  1147.   FillTestCode(Sel, 0, Sizes[0]*256, 0 );
  1148.   Counts[0] = CallTestCode(Sel, 0);
  1149.   
  1150.   for (i=1; Sizes[i] !=MaxCacheSize; i++)
  1151.   { FillTestCode(Sel, 0, Sizes[i]*256, 0 );
  1152.     Counts[i] = CallTestCode(Sel, 0);
  1153.     
  1154. #ifdef DEBUG
  1155.     fprintf(stdout,"Size %ldKB Count:%ld rate:%f\n",Sizes[i],Counts[i]/Sizes[i],(double)(Counts[i]/Sizes[i])/(double)(Counts[i-1]/Sizes[i-1]));
  1156. #endif
  1157.     if( (double)(Counts[i]/Sizes[i])/(double)(Counts[i-1]/Sizes[i-1]) > 1.5)
  1158.     { CacheLayer++;
  1159.       fprintf(stdout,"L%d cache size %dKB \n",CacheLayer,Sizes[i-1]);
  1160.     }
  1161.     if ( (double)(MaxCacheCount/(EcacheSize/256))/(double)(Counts[i]/Sizes[i]) < 1.2 ) break;
  1162.   }
  1163.  
  1164.  
  1165. }
  1166.  
  1167.