int main() { unsigned int i; #if defined(TARGET_WINDOWS) && TARGET_WINDOWS == 32 && !defined(WIN386) /* As a 32-bit Windows application, we *can* talk directly to the 8254 but only if running under Windows 3.1/95/98/ME. * Windows NT would never permit us to directly talk to IO. * * However if we're a Win16 program or Watcom 386 application, Windows NT will trap and emulate the 8254 through NTVDM.EXE */ detect_windows(); if (!(windows_mode == WINDOWS_REAL || windows_mode == WINDOWS_STANDARD || windows_mode == WINDOWS_ENHANCED)) { printf("This test program is only applicable to Windows 3.x/9x\n"); return 1; } #endif printf("8254 library test program\n"); if (!probe_8254()) { printf("Chip not present. Your computer might be 2010-era hardware that dropped support for it.\n"); return 1; } printf("This program tests the ability for emulation to handle\n"); printf("rapid changes to PC speaker frequency.\n"); printf("Apogee/Duke Nukem style sound effects.\n"); #if defined(NO_PORT_43) # undef write_8254_pc_speaker #endif write_8254_system_timer(0); /* restore normal function to prevent BIOS from going crazy */ write_8254_pc_speaker(0); /* make sure the PIT timer is in mode 3 (square wave) */ printf("Rapid ramping (entry)\n"); play_sfx(duke_entry); printf("Rapid ramping (entry) alternate with extra delay\n"); play_sfx(duke_entry_alt); printf("Rapid ramping (item)\n"); for (i=0;i < 8;i++) play_sfx(duke_item); printf("Rapid ramping (item) alternate\n"); for (i=0;i < 8;i++) play_sfx(duke_item_alt); write_8254_system_timer(0); /* restore normal function to prevent BIOS from going crazy */ return 0; }
int main(int argc,char **argv) { struct acpi_rsdt_header sdth; acpi_memaddr_t addr; unsigned long i,max; uint32_t tmp32,tmplen; char tmp[32]; for (i=1;i < (unsigned long)argc;) { const char *a = argv[(unsigned int)(i++)]; if (*a == '-' || *a == '/') { do { a++; } while (*a == '-' || *a == '/'); if (!strcmp(a,"?") || !strcmp(a,"h") || !strcmp(a,"help")) { help(); return 1; } else if (!strcmp(a,"32")) { acpi_use_rsdt_32 = 1; } else { fprintf(stderr,"Unknown switch '%s'\n",a); help(); return 1; } } else { fprintf(stderr,"Unknown arg '%s'\n",a); help(); return 1; } } if (!probe_8254()) { printf("Cannot init 8254 timer\n"); return 1; } if (!probe_8259()) { printf("Cannot init 8259 PIC\n"); return 1; } cpu_probe(); probe_dos(); detect_windows(); #if TARGET_MSDOS == 32 probe_dpmi(); dos_ltp_probe(); #endif #if TARGET_MSDOS == 16 if (!flatrealmode_setup(FLATREALMODE_4GB)) { printf("Unable to set up flat real mode (needed for 16-bit builds)\n"); printf("Most ACPI functions require access to the full 4GB range.\n"); return 1; } #endif if (!acpi_probe()) { printf("ACPI BIOS not found\n"); return 1; } assert(acpi_rsdp != NULL); printf("ACPI %u.0 structure at 0x%05lX\n",acpi_rsdp->revision+1,(unsigned long)acpi_rsdp_location); memcpy(tmp,(char*)(&(acpi_rsdp->OEM_id)),6); tmp[6]=0; printf("ACPI OEM ID '%s', RSDT address (32-bit) 0x%08lX Length %lu\n",tmp, (unsigned long)(acpi_rsdp->rsdt_address), (unsigned long)(acpi_rsdp->length)); if (acpi_rsdp->revision != 0) printf(" XSDT address (64-bit) 0x%016llX\n", (unsigned long long)(acpi_rsdp->xsdt_address)); printf("Chosen RSDT/XSDT at 0x%08llX\n",(unsigned long long)acpi_rsdt_location); if (acpi_rsdt != NULL) { memcpy(tmp,(void*)(acpi_rsdt->signature),4); tmp[4] = 0; printf(" '%s': len=%lu rev=%u\n",tmp,(unsigned long)acpi_rsdt->length, acpi_rsdt->revision); memcpy(tmp,(void*)(acpi_rsdt->OEM_id),6); tmp[6] = 0; printf(" OEM id: '%s'\n",tmp); memcpy(tmp,(void*)(acpi_rsdt->OEM_table_id),8); tmp[8] = 0; printf(" OEM table id: '%s' rev %lu\n",tmp, (unsigned long)acpi_rsdt->OEM_revision); memcpy(tmp,(void*)(&(acpi_rsdt->creator_id)),4); tmp[4] = 0; printf(" Creator: '%s' rev %lu\n",tmp, (unsigned long)acpi_rsdt->creator_revision); } max = acpi_rsdt_entries(); if (acpi_rsdt_is_xsdt()) { printf("Showing XSDT, %lu entries\n",max); } else { printf("Showing RSDT, %lu entries\n",max); } for (i=0;i < max;i++) { addr = acpi_rsdt_entry(i); printf(" [%lu] 0x%08llX ",i,(unsigned long long)addr); if (addr != 0ULL) { tmp32 = acpi_mem_readd(addr); tmplen = 0; memcpy(tmp,&tmp32,4); tmp[4] = 0; if (acpi_probe_rsdt_check(addr,tmp32,&tmplen)) { acpi_memcpy_from_phys(&sdth,addr,sizeof(struct acpi_rsdt_header)); printf("'%s' len=0x%lX rev=%u ",tmp,(unsigned long)tmplen,sdth.revision); memcpy(tmp,&sdth.OEM_id,6); tmp[6] = 0; printf("OEM id: '%s'\n",tmp); memcpy(tmp,&sdth.OEM_table_id,8); tmp[8] = 0; printf("OEM table id: '%s' rev %u ",tmp,sdth.OEM_revision); memcpy(tmp,&sdth.creator_id,4); tmp[4] = 0; printf("Creator id: '%s' rev %u",tmp,sdth.creator_revision); if (!memcmp(sdth.signature,"MCFG",4)) { struct acpi_mcfg_entry entry; uint64_t o = addr + 44; unsigned int count; printf("\nPCI Express map:"); assert(sizeof(struct acpi_mcfg_entry) == 16); count = (unsigned int)(tmplen / sizeof(struct acpi_mcfg_entry)); while (count != 0) { acpi_memcpy_from_phys(&entry,o,sizeof(struct acpi_mcfg_entry)); o += sizeof(struct acpi_mcfg_entry); /* Some bioses I test against seem to return enough for 3 but fill in only 1? */ if (entry.base_address != 0ULL || entry.start_pci_bus_number != 0 || entry.end_pci_bus_number != 0) { uint64_t sz; if (entry.start_pci_bus_number > entry.end_pci_bus_number) entry.start_pci_bus_number = entry.end_pci_bus_number; sz = (((unsigned long long)(entry.end_pci_bus_number - entry.start_pci_bus_number)) + 1ULL) << 20ULL; printf("\n @0x%08llX-0x%08llX seg=%u bus=%u-%u", (unsigned long long)entry.base_address, (unsigned long long)(entry.base_address + sz - 1ULL), (unsigned int)entry.pci_segment_group_number, (unsigned int)entry.start_pci_bus_number, (unsigned int)entry.end_pci_bus_number); } count--; } } } else { printf("'%s' check failed",tmp); } } printf("\n"); } acpi_free(); return 0; }
int main(int argc,char **argv) { unsigned int req_ver = 0; unsigned int dont_disconnect = 0; unsigned int req_mode = APM_CONNECT_NONE; const char *action = NULL; int i; for (i=1;i < argc;) { const char *a = argv[i++]; if (*a == '/' || *a == '-') { do { a++; } while (*a == '/' || *a == '-'); if (!strncmp(a,"v1.",3)) { a += 3; req_ver = 0x100 + (atoi(a) & 0xFF); } else if (!strcmp(a,"vn")) { req_ver = REQ_VER_NONE; } else if (!strcmp(a,"nd")) { dont_disconnect = 1; } else if (!strcmp(a,"h") || !strcmp(a,"help")) { help(); } else if (!strncmp(a,"if:",3)) { a += 3; if (!strcmp(a,"real")) req_mode = APM_CONNECT_REALMODE; else if (!strcmp(a,"16pm")) req_mode = APM_CONNECT_16_PM; else if (!strcmp(a,"32pm")) req_mode = APM_CONNECT_32_PM; else { fprintf(stderr,"Unknown interface %s\n",a); return 1; } } else { fprintf(stderr,"Unknown param '%s'\n",a); help(); return 1; } } else if (action == NULL) { action = a; } else { fprintf(stderr,"Unknown param\n"); return 1; } } if (!probe_8254()) { printf("Cannot init 8254 timer\n"); return 1; } if (!probe_8259()) { printf("Cannot init 8259 PIC\n"); return 1; } probe_dos(); detect_windows(); if (!apm_bios_probe()) { printf("APM BIOS not found\n"); return 1; } if (req_mode == APM_CONNECT_NONE) req_mode = APM_CONNECT_REALMODE; printf("APM BIOS v%u.%u: ",apm_bios->major,apm_bios->minor); if (apm_bios->flags & APM_FL_16BIT_PM) printf("[16-bit pm] "); if (apm_bios->flags & APM_FL_32BIT_PM) printf("[32-bit pm] "); if (apm_bios->flags & APM_FL_CPU_IDLE_SLOWS) printf("[cpu-idle-slow] "); if (apm_bios->flags & APM_FL_PM_DISABLED) printf("[disabled] "); if (apm_bios->flags & APM_FL_PM_DISENGAGED) printf("[disengaged] "); printf("\n"); if (req_ver >= 0x100) apm_bios->version_want = req_ver; if (req_ver != REQ_VER_NONE) { if (!apm_bios_connect(req_mode)) { fprintf(stderr,"Failed to connect to APM BIOS (last=0x%02X)\n",apm_bios->last_error); return 1; } printf("Connected to APM BIOS v%u.%u interface\n",apm_bios->major_neg,apm_bios->minor_neg); printf(" batteries: %u\n",apm_bios->batteries); printf(" capabilities:\n"); if (apm_bios->capabilities & 1) printf(" Can enter global standby state\n"); if (apm_bios->capabilities & 2) printf(" Can enter global suspend state\n"); if (apm_bios->capabilities & 4) printf(" Resume timer will wake from standby\n"); if (apm_bios->capabilities & 8) printf(" Resume timer will wake from suspend\n"); if (apm_bios->capabilities & 16) printf(" Resume on ring will wake from standby\n"); if (apm_bios->capabilities & 32) printf(" Resume on ring will wake from suspend\n"); if (apm_bios->capabilities & 64) printf(" PCMCIA ring indicator will wake up from standby\n"); if (apm_bios->capabilities & 128) printf(" PCMCIA ring indicator will wake up from suspend\n"); printf("\n"); } if (action == NULL) { } else if (!strcmp(action,"cpu-idle")) { printf("Issuing CPU idle command\n"); if (!apm_bios_cpu_idle()) fprintf(stderr,"CPU Idle failed\n"); } else if (!strcmp(action,"cpu-busy")) { printf("Issuing CPU busy command\n"); if (!apm_bios_cpu_busy()) fprintf(stderr,"CPU Busy failed\n"); } else if (!strcmp(action,"events")) { while (1) { signed long ev = apm_bios_pm_evnet(); if (ev >= 0LL) { printf("Event 0x%04X\n",(unsigned int)ev); } if (kbhit()) { if (getch() == 27) break; } } } else if (!strcmp(action,"status")) { apm_bios_update_status(); printf("AC=0x%X Batt=0x%X BattFlag=0x%X BattPercent=%u BattLife=%u%s\n", apm_bios->status_ac, apm_bios->status_battery, apm_bios->status_battery_flag, apm_bios->status_battery_life, apm_bios->status_battery_time&0x7FFF, (apm_bios->status_battery_time&0x8000)?"m":"s"); } else if (!strcmp(action,"standby")) { if (!apm_bios_power_state(APM_POWER_STANDBY)) fprintf(stderr,"Unable to set power state\n"); } else if (!strcmp(action,"suspend")) { if (!apm_bios_power_state(APM_POWER_SUSPEND)) fprintf(stderr,"Unable to set power state\n"); } else if (!strcmp(action,"off")) { if (!apm_bios_power_state(APM_POWER_OFF)) fprintf(stderr,"Unable to set power state\n"); } if (req_ver != REQ_VER_NONE && !dont_disconnect) { if (!apm_bios_connect(APM_CONNECT_NONE)) { fprintf(stderr,"Failed to disconnect\n"); } printf("Disconnected APM BIOS\n"); } return 0; }
int main() { struct t8254_readback_t readback; t8254_time_t tick[3]; unsigned int i; printf("8254 library test program\n"); if (!probe_8254()) { printf("Chip not present. Your computer might be 2010-era hardware that dropped support for it.\n"); return 1; } if (!probe_8259()) { printf("8259 interrupt controller not present. Your computer might be 2010-era hardware that dropped support for it.\n"); return 1; } printf("8254 base clock: %luHz\n",T8254_REF_CLOCK_HZ); speaker_rate = T8254_REF_CLOCK_HZ / 400UL; /* 400Hz */ prev_irq0 = _dos_getvect(T8254_IRQ+0x08); _dos_setvect(T8254_IRQ+0x8,irq0); _cli(); write_8254_pc_speaker(speaker_rate); write_8254_system_timer(max); _sti(); #ifdef TARGET_PC98 /* PC-98 does not have IRQ0 running by default */ p8259_unmask(T8254_IRQ); #endif while (1) { if (kbhit()) { int c = getch(); if (c == 27) break; else if (c == '-') { max -= 80; if (max > (0xFFFF-80)) max = 0xFFFF; _cli(); write_8254_system_timer(max); _sti(); } else if (c == '=') { max += 110; if (max < 110 || max > (0xFFFF-110)) max = 0xFFFF; _cli(); write_8254_system_timer(max); _sti(); } /* play with timer 2 and the PC speaker gate */ else if (c == 'p') { unsigned char on = (t8254_pc_speaker_read_gate() != 0) ? 1 : 0; if (on) t8254_pc_speaker_set_gate(0); else t8254_pc_speaker_set_gate(3); } else if (c == '1') { #ifndef TARGET_PC98 unsigned char v = t8254_pc_speaker_read_gate(); t8254_pc_speaker_set_gate(v ^ PC_SPEAKER_OUTPUT_TTL_AND_GATE); #endif } else if (c == '2') { #ifndef TARGET_PC98 unsigned char v = t8254_pc_speaker_read_gate(); t8254_pc_speaker_set_gate(v ^ PC_SPEAKER_COUNTER_2_GATE); #endif } else if (c == '[') { speaker_rate += 110; if (speaker_rate > (0xFFFF-110) || speaker_rate < 110) speaker_rate = 0xFFFF; write_8254_pc_speaker(speaker_rate); } else if (c == ']') { speaker_rate -= 110; if (speaker_rate > (0xFFFF-110)) speaker_rate = 0; write_8254_pc_speaker(speaker_rate); } else if (c == 'w') { printf("\n"); pulse_width_test(); _cli(); write_8254_system_timer(max); _sti(); printf("\n"); } else if (c == 'z') { /* sleep-wait loop test */ unsigned long delay_ticks; unsigned long z; unsigned int c,cmax; printf("\nDelay interval in us? "); z = 1000000; scanf("%lu",&z); delay_ticks = t8254_us2ticks(z); printf(" %lu = %lu ticks\n",z,delay_ticks); if (delay_ticks == 0UL) cmax = (unsigned int)(T8254_REF_CLOCK_HZ / 20UL); else cmax = (unsigned int)(T8254_REF_CLOCK_HZ / 20UL / (unsigned long)delay_ticks); if (cmax == 0) cmax = 1; write_8254_pc_speaker(T8254_REF_CLOCK_HZ / 400UL); /* tick as fast as possible */ while (1) { if (kbhit()) { if (getch() == 27) break; } for (c=0;c < cmax;c++) { t8254_pc_speaker_set_gate(3); t8254_wait(delay_ticks); t8254_pc_speaker_set_gate(0); t8254_wait(delay_ticks); } } } else if (c == 'd') { printf("\n \nDetail mode, hit 'd' again to exit: [WARNING: 8254 only]\n"); while (1) { if (kbhit()) { int c = getch(); if (c == 'd') { break; } } _cli(); readback_8254(T8254_READBACK_ALL,&readback); _sti(); printf("\x0D"); for (i=0;i <= 2;i++) { printf("[%u] stat=%02x count=%04x ",i, readback.timer[i].status, readback.timer[i].count); } fflush(stdout); } printf("\n"); } } for (i=0;i <= 2;i++) tick[i] = read_8254(i); /* BUG: DOSBox/DOSBox-X appear to have a bug where the PC speaker readback toggles * regardless of the GATE input to Counter 2. Bring GATE low (setting bit 1 * of port 61h to 0) is supposed to cause Counter 2 to stop. The AND gate * after the output (bit 0 of port 61h) is not supposed to affect the readback. */ printf("\x0D %04x %04x %04x max=%04x count=%04x SPKR=%u",tick[0],tick[1],tick[2], max,counter,read_8254_pc_speaker_output()!=0?1:0); fflush(stdout); } printf("\n"); #ifdef TARGET_PC98 /* PC-98 does not have IRQ0 running by default */ p8259_mask(T8254_IRQ); #endif _cli(); write_8254_pc_speaker(0); t8254_pc_speaker_set_gate(0); _dos_setvect(T8254_IRQ+0x8,prev_irq0); _sti(); write_8254_system_timer(0xFFFF); /* restore normal function to prevent BIOS from going crazy */ return 0; }
int main() { #if defined(TARGET_WINDOWS) HWND hwnd; #endif unsigned char redraw; int c; probe_dos(); detect_windows(); #if !defined(TARGET_WINDOWS) if (!probe_8254()) { printf("8254 not found (I need this for time-sensitive portions of the driver)\n"); return 1; } #endif #if defined(TARGET_WINDOWS) # ifdef WIN_STDOUT_CONSOLE hwnd = _win_hwnd(); # else hwnd = GetFocus(); printf("WARNING: The Win32 console version is experimental. It generally works...\n"); printf(" but can run into problems if focus is taken or if the console window\n"); printf(" is started minimized or maximized. ENTER to continue, ESC to cancel.\n"); printf(" If this console is full-screen, hit ALT+ENTER to switch to window.\n"); do { c = getch(); if (c == 27) return 1; } while (c != 13); # endif # if TARGET_WINDOWS == 32 if (!InitWin16EB()) { MessageBox(hwnd,"Failed to init win16eb","Win16eb",MB_OK); return 1; } # endif /* setup DISPDIB */ if (DisplayDibLoadDLL()) { MessageBox(hwnd,dispDibLastError,"Failed to load DISPDIB.DLL",MB_OK); return 1; } if (DisplayDibCreateWindow(hwnd)) { MessageBox(hwnd,dispDibLastError,"Failed to create DispDib window",MB_OK); return 1; } if (DisplayDibGenerateTestImage()) { MessageBox(hwnd,dispDibLastError,"Failed to generate test card",MB_OK); return 1; } if (DisplayDibDoBegin()) { MessageBox(hwnd,dispDibLastError,"Failed to begin display",MB_OK); return 1; } #endif if (!probe_vga()) { #if defined(TARGET_WINDOWS) DisplayDibDoEnd(); DisplayDibUnloadDLL(); MessageBox(hwnd,"Probe failed","VGA lib",MB_OK); #else printf("VGA probe failed\n"); #endif return 1; } int10_setmode(3); update_state_from_vga(); redraw = 1; while (1) { if (redraw) { /* position the cursor to home */ vga_moveto(0,0); vga_sync_bios_cursor(); printf("ESC Exit to DOS A. 320x200x256 VGA\n"); } c = getch(); if (c == 27) break; else if (c == 'a' || c == 'A') v320x200x256_VGA_menu(); } #if defined(TARGET_WINDOWS) DisplayDibDoEnd(); if (DisplayDibUnloadDLL()) MessageBox(hwnd,dispDibLastError,"Failed to unload DISPDIB.DLL",MB_OK); # if TARGET_MSDOS == 32 FreeWin16EB(); # endif #endif return 0; }
int main(int argc,char *argv[],char *envp[]) { rdtsc_t start,measure,ticks_per_sec; unsigned char force = 0; double t; int c; { int i = 1; char *a; while (i < argc) { a = argv[i++]; if (*a == '-') { do { a++; } while (*a == '-'); if (!strcmp(a,"f") || !strcmp(a,"force")) force = 1; else return 1; } else { return 1; } } } cpu_probe(); printf("Your CPU is basically a %s or higher\n",cpu_basic_level_to_string(cpu_basic_level)); if (cpu_v86_active) printf(" - Your CPU is currently running me in virtual 8086 mode\n"); if (force) { printf(" - You're forcing me to use RDTSC. I may crash if your CPU doesn't\n"); printf(" support it or the environment doesn't enable it.\n"); printf(" OK! Here we go....!\n"); } else { if (!(cpu_flags & CPU_FLAG_CPUID)) { printf(" - Your CPU doesn't support CPUID, how can it support RDTSC?\n"); return 1; } if (!(cpu_cpuid_features.a.raw[2] & 0x10)) { printf(" - Your CPU does not support RDTSC\n"); return 1; } if (cpu_flags & CPU_FLAG_DONT_USE_RDTSC) { printf(" - Your CPU does support RDTSC but it's not recommended in this environment.\n"); printf(" This is usually due to running a 16-bit build in pure DOS under EMM386.EXE.\n"); return 1; } } #if defined(TARGET_OS2) # if TARGET_MSDOS == 32 /* OS/2 32-bit: We can use DosQuerySysInfo() */ printf("Measuring CPU speed, using DosQuerySysInfo(), over 3 seconds\n"); { ULONG startTick,tmp; start = cpu_rdtsc(); startTick = GetMsCount(); do { tmp = GetMsCount(); } while ((tmp - startTick) < 3000); /* NTS: <- I know this rolls over in 49 days, the math though should overflow the 32-bit integer and produce correct results anyway */ measure = cpu_rdtsc(); /* use the precise tick count to better compute ticks_per_sec */ ticks_per_sec = ((measure - start) * 1000ULL) / ((rdtsc_t)(tmp - startTick)); printf("Measurement: %lums = %lld ticks\n",tmp - startTick,(int64_t)ticks_per_sec); printf(" From 0x%llX to 0x%llX\n",start,measure); } # else /* OS/2 16-bit: There is no API (that I know of) to get tick count. Use system clock. */ printf("Measuring CPU speed, using system clock with 1-second resolution, across 3 seconds\n"); { time_t startTick,tmp; /* wait for the immediate start of a one-second tick, then record RDTSC and count until 3 seconds */ startTick = time(NULL); do { tmp = time(NULL); } while (tmp == startTick); start = cpu_rdtsc(); startTick = tmp; /* NOW! Count 3 seconds and measure CPU ticks */ do { tmp = time(NULL); } while ((tmp - startTick) < 3); measure = cpu_rdtsc(); /* use the precise tick count to better compute ticks_per_sec */ ticks_per_sec = ((measure - start) * 1ULL) / ((rdtsc_t)(tmp - startTick)); printf("Measurement: %lu seconds = %lld ticks\n",tmp - startTick,(int64_t)ticks_per_sec); printf(" From 0x%llX to 0x%llX\n",start,measure); } # endif #elif defined(TARGET_WINDOWS) # if TARGET_MSDOS == 16 /* Windows 2.x/3.0/3.1: Use GetTickCount() or * Windows 3.1: Use TOOLHELP.DLL TimerCount() which is more accurate (really?) */ if (ToolHelpInit()) { TIMERINFO ti; ti.dwSize = sizeof(ti); printf("Measuring CPU speed, using TOOLHELP TimerCount() over 1 second\n"); { DWORD startTick,tmp; start = cpu_rdtsc(); if (!__TimerCount(&ti)) { printf("TimerCount() failed\n"); return 1; } startTick = ti.dwmsSinceStart; do { # if defined(WIN_STDOUT_CONSOLE) _win_pump(); /* <- you MUST call this. The message pump must run, or else the timer won't advance and this loop will run forever. The fact that GetTickCount() depends on a working message pump under Windows 3.1 seems to be a rather serious oversight on Microsoft's part. Note that the problem described here does not apply to Windows 9x/ME. Also note the Toolhelp function TimerCount() relies on GetTickCount() as a basic for time (though Toolhelp uses VxD services or direct I/O port hackery to refine the timer count) */ # endif if (!__TimerCount(&ti)) { printf("TimerCount() failed\n"); return 1; } tmp = ti.dwmsSinceStart; } while ((tmp - startTick) < 1000); /* NTS: <- I know this rolls over in 49 days, the math though should overflow the 32-bit integer and produce correct results anyway */ measure = cpu_rdtsc(); /* use the precise tick count to better compute ticks_per_sec */ ticks_per_sec = ((measure - start) * 1000ULL) / ((rdtsc_t)(tmp - startTick)); printf("Measurement: %lums = %lld ticks\n",tmp - startTick,(int64_t)ticks_per_sec); printf(" From 0x%llX to 0x%llX\n",start,measure); } } else { # else { # endif printf("Measuring CPU speed, using GetTickCount() over 3 second\n"); { DWORD startTick,tmp; start = cpu_rdtsc(); startTick = GetTickCount(); /* NTS: Dunno yet about Windows 3.1, but Windows 95 seems to require we Yield(). If we don't, the GetTickCount() return * value never updates and we're forever stuck in a loop. */ do { # if defined(WIN_STDOUT_CONSOLE) _win_pump(); /* <- you MUST call this. The message pump must run, or else the timer won't advance and this loop will run forever. The fact that GetTickCount() depends on a working message pump under Windows 3.1 seems to be a rather serious oversight on Microsoft's part. Note that the problem described here does not apply to Windows 9x/ME */ # endif tmp = GetTickCount(); } while ((tmp - startTick) < 3000); /* NTS: <- I know this rolls over in 49 days, the math though should overflow the 32-bit integer and produce correct results anyway */ measure = cpu_rdtsc(); /* use the precise tick count to better compute ticks_per_sec */ ticks_per_sec = ((measure - start) * 1000ULL) / ((rdtsc_t)(tmp - startTick)); printf("Measurement: %lums = %lld ticks\n",tmp - startTick,(int64_t)ticks_per_sec); printf(" From 0x%llX to 0x%llX\n",start,measure); } } #else /* MS-DOS: Init the 8254 timer library for precise measurement */ if (!probe_8254()) { printf("Cannot init 8254 timer\n"); return 1; } /* DOSBox-X and most motherboards leave the PIT in a mode that counts down by 2. * Our code sets the counter and puts it in a mode that counts down by 1. * We have to do this or our wait functions exit in half the time (which explains * why testing this code in DOSBox-X often comes up with RDTSC running at 2x * normal speed. */ write_8254_system_timer(0); /* 18.2 tick/sec on our terms (proper PIT mode) */ printf("Measuring CPU speed (relative to 8254 timer)\n"); _cli(); start = cpu_rdtsc(); t8254_wait(t8254_us2ticks(1000000)); measure = cpu_rdtsc(); _sti(); printf("Measurement: 1 sec = %lld ticks\n",(int64_t)(measure - start)); printf(" From 0x%llX to 0x%llX\n",start,measure); ticks_per_sec = (measure - start); #endif if ((int64_t)ticks_per_sec < 0) { printf("Cannot determine CPU cycle count\n"); ticks_per_sec = 100000ULL; } while (1) { measure = cpu_rdtsc(); t = (double)((int64_t)(measure - start)); t /= ticks_per_sec; printf("\x0D" "0x%llX = %.3f ",measure,t); #if !defined(WINFCON_STOCK_WIN_MAIN) fflush(stdout); /* FIXME: The fake console code should intercept fflush() too */ #endif if (kbhit()) { c = getch(); if (c == 0) c = getch() << 8; if (c == 27) break; else if (c == 'r' || c == 'R') { if (c == 'r' || (cpu_flags & CPU_FLAG_DONT_WRITE_RDTSC)) { printf("\nI am not able to write the TSC register within this environment\nYou can force me by typing SHIFT+R, don't blame me when I crash...\n"); } else { printf("\nUsing MSR to reset TSC to 0\n"); /* demonstrating WRMSR to write the TSC (yes, you can!) */ cpu_rdtsc_write(start = 0ULL); printf("Result: 0x%llX\n",cpu_rdtsc()); } } else if (c == 's') { if (c == 's' && (cpu_flags & CPU_FLAG_DONT_WRITE_RDTSC)) { printf("\nI am not able to write the TSC register within this environment\nYou can force me by typing SHIFT+S, don't blame me when I crash...\n"); } else { printf("\nUsing MSR to reset TSC to 0x123456789ABCDEF\n"); /* demonstrating WRMSR to write the TSC (yes, you can!) */ cpu_rdtsc_write(start = 0x123456789ABCDEFULL); printf("Result: 0x%llX\n",cpu_rdtsc()); } } } } printf("\n"); return 0; }
int main(int argc,char **argv,char **envp) { unsigned int patience; char tmps[128]; uint32_t tmp; probe_dos(); detect_windows(); if (windows_mode == WINDOWS_NT) { printf("This program is not compatible with Windows NT\n"); return 1; } #if defined(TARGET_WINDOWS) && TARGET_MSDOS == 32 && !defined(WIN386) #else if (!probe_8254()) { printf("8254 not found (I need this for time-sensitive portions of the driver)\n"); return 1; } #endif if (!probe_dosbox_id()) { printf("DOSBox integration device not found\n"); return 1; } printf("DOSBox integration device found at I/O port %xh\n",dosbox_id_baseio); if (probe_dosbox_id_version_string(tmps,sizeof(tmps))) printf("DOSBox version string: '%s'\n",tmps); else printf("DOSBox version string N/A\n"); /* first check that the screenshot function is available */ dosbox_id_write_regsel(DOSBOX_ID_REG_SCREENSHOT_TRIGGER); tmp = dosbox_id_read_data(); if (tmp & DOSBOX_ID_SCREENSHOT_STATUS_NOT_AVAILABLE) { printf("DOSBox screenshot control register not available\n"); return 1; } else if (tmp & DOSBOX_ID_SCREENSHOT_STATUS_NOT_ENABLED) { printf("DOSBox screenshot control register not enabled\n"); return 1; } if (tmp & DOSBOX_ID_SCREENSHOT_STATUS_IMAGE_IN_PROGRESS) printf("WARNING: Screenshot already in progress\n"); printf("Triggering DOSBox screenshot function\n"); dosbox_id_debug_message("Triggering screenshot function\n"); /* trigger it */ dosbox_id_write_regsel(DOSBOX_ID_REG_SCREENSHOT_TRIGGER); dosbox_id_write_data(DOSBOX_ID_SCREENSHOT_IMAGE); /* did it trigger it? */ dosbox_id_write_regsel(DOSBOX_ID_REG_SCREENSHOT_TRIGGER); tmp = dosbox_id_read_data(); if (!(tmp & DOSBOX_ID_SCREENSHOT_STATUS_IMAGE_IN_PROGRESS)) { printf("DOSBox screenshot trigger failed.\n"); return 1; } /* wait for the screenshot to happen. * DOSBox will write the screenshot when VGA vertical retrace happens, which should be 1/70th of a second. * So if it doesn't happen within 1 second, then it failed. */ #if defined(TARGET_WINDOWS) && TARGET_MSDOS == 32 && !defined(WIN386) patience = 10; /* 1 second (10 x 100ms) (Windows 9x scheduler isn't THAT good!) */ #else patience = 1000; /* 1 second (1000 x 1ms) */ #endif do { if (--patience == 0) { printf("DOSBox failed to take screenshot (timeout)\n"); return 1; } #if defined(TARGET_WINDOWS) && TARGET_MSDOS == 32 && !defined(WIN386) Sleep(100); /* 100ms */ #else t8254_wait(t8254_us2ticks(1000)); /* 1ms */ #endif dosbox_id_write_regsel(DOSBOX_ID_REG_SCREENSHOT_TRIGGER); tmp = dosbox_id_read_data(); } while (tmp & DOSBOX_ID_SCREENSHOT_STATUS_IMAGE_IN_PROGRESS); printf("Screenshot done\n"); return 0; }