kmain() { terminal_init(); setup_IDT_entry (&idt[0x08], 0x08, (dword)&_int_08_hand, ACS_INT, 0); setup_IDT_entry (&idt[0x09], 0x08, (dword)&_int_09_hand, ACS_INT, 0); setup_IDT_entry (&idt[0x74], 0x08, (dword)&_int_74_hand, ACS_INT, 0); setup_IDT_entry (&idt[0x80], 0x08, (dword)&_int_80_hand, ACS_INT, 0); /* IDTR Setting */ idtr.base = 0; idtr.base +=(dword) &idt; idtr.limit = sizeof(idt)-1; _lidt(&idtr); /* Interrupt unmasking */ _cli(); _maskPIC1(0xF8); /*0XF8*/ _maskPIC2(0xEF); /*0XEF*/ _sti(); video_init(); timertick_init(); rtc_init(); mouse_init(); shell_run(); }
PUBLIC void _expandStack() { _cli(); PROCESS *proc = scheduler_getCurrentProcess(); proc->stack -= PAGE_SIZE; proc->stacksize += PAGE_SIZE; // FIXME: check for used pages. get_page(proc->stack, true, current_directory); log(L_DEBUG, "EXPANDED: %s starts at 0x%x to 0x%x", proc->name, proc->stack, proc->stack + proc->stacksize - 1); printf("STACK EXPANDED: %s starts at 0x%x to 0x%x (esp: 0x%x)\n", proc->name, proc->stack, proc->stack + proc->stacksize - 1, proc->ESP); }
static int soundblaster_stop_playback(soundcard_t sc) { struct sndsb_ctx *card = soundblaster_get_sndsb_ctx(sc); if (card == NULL) return -1; if (!sc->wav_state.playing) return 0; _cli(); soundblaster_update_wav_dma_position(sc,card); soundblaster_update_wav_play_delay(sc,card); _sti(); sndsb_stop_dsp_playback(card); _cli(); sc->wav_state.playing = 0; _sti(); return 0; }
int probe_8259() { unsigned char om,cm,c2; unsigned int flags; if (p8259_probed < 0) return (int)p8259_probed; /* don't let the BIOS fiddle with the mask during the test. Fixes: Pentium machine where 1 out of 100 times programs fail with "cannot init PIC" */ flags = get_cpu_flags(); _cli(); om = p8259_read_mask(0); p8259_write_mask(0,0xFF); cm = p8259_read_mask(0); p8259_write_mask(0,0x00); c2 = p8259_read_mask(0); p8259_write_mask(0,om); set_cpu_flags(flags); if (cm != 0xFF || c2 != 0x00) return (p8259_probed=0); /* is a slave present too? */ flags = get_cpu_flags(); _cli(); om = p8259_read_mask(8); p8259_write_mask(8,0xFF); cm = p8259_read_mask(8); p8259_write_mask(8,0x00); c2 = p8259_read_mask(8); p8259_write_mask(8,om); set_cpu_flags(flags); if (cm == 0xFF && c2 == 0x00) p8259_slave_present = 1; return (p8259_probed=1); }
void keDoSched() { uint32 i; uint32 j; _cli(); i=keSchedNextTask(); while(i==0xFFFFFFFF) { _sti(); _hlt(); _cli(); i=keSchedNextTask(); } // not any task can be sched if(i==currentTaskId) { _sti(); return; // only the current task can be sched } j=currentTaskId; currentTaskId=i; _switch(&(tasks[i]->esp), &(tasks[j]->esp)); }
void _stdcall main(unsigned long p1, unsigned long p2, unsigned long p3) { uint32 *oldesp; struct taskblock *task; _cli(); cpuInit(); _ISRVECT[17]=(uint32)keDoSched; _ISRVECT[32]=(uint32)keTimerIsr; keKernelHeapInit(); keInitTaskSystem(); task=keNewTask("main", keEntryMain, 0, 8, 0x4000); currentTaskId=0; _switch(&(task->esp), &oldesp); }
static int soundblaster_start_playback(soundcard_t sc) { struct sndsb_ctx *card = soundblaster_get_sndsb_ctx(sc); if (card == NULL) return -1; if (!sc->wav_state.prepared) return -1; if (sc->wav_state.playing) return 0; if (!sndsb_begin_dsp_playback(card)) return -1; _cli(); sc->wav_state.playing = 1; _sti(); return 0; }
void generalprotectintr(uint32 edi, uint32 esi, uint32 ebp, uint32 esp, uint32 ebx, uint32 edx, uint32 ecx, uint32 eax, uint32 code, uint32 eip, uint32 cs) { int i; _cli(); printf("\nGeneral Protect Error\n"); printf("tid=%d\n", currentTaskId); printf("eip=%08x ecs=%08x code=%08x\n", eip, cs, code); printf("eax=%08x ebx=%08x ecx=%08x edx=%08x\n", eax, ebx, ecx, edx); printf("esp=%08x ebp=%08x esi=%08x edi=%08x\n", esp, ebp, esi, edi); printf("Dump Stack:\n"); for(i=0;i<16;i++) printf("%08X ", ((uint32*)esp)[i+3]); printf("Dump TCB:\n"); for(i=0;i<16;i++) printf("%08X ", ((uint32*)tasks[currentTaskId])[i]); while(1); }
void direct_dac_test(void) { unsigned long time,bytes; unsigned char FAR *ptr; unsigned int i,count; unsigned int pc,c; doubleprintf("Direct DAC playback test.\n"); /* FIXME: Why is the final rate SLOWER in DOSBox-X in 386 protected mode? */ sndsb_reset_dsp(sb_card); sndsb_write_dsp(sb_card,0xD1); /* speaker on */ _cli(); time = 0; bytes = 0; c = read_8254(T8254_TIMER_INTERRUPT_TICK); for (count=0;count < 3;count++) { ptr = sb_dma->lin; for (i=0;i < sb_dma->length;i++) { sndsb_write_dsp(sb_card,SNDSB_DSPCMD_DIRECT_DAC_OUT); /* 0x10 */ sndsb_write_dsp(sb_card,*ptr++); pc = c; c = read_8254(T8254_TIMER_INTERRUPT_TICK); time += (unsigned long)((pc - c) & 0xFFFFU); /* remember: it counts DOWN. assumes full 16-bit count */ } bytes += sb_dma->length; } _sti(); if (time == 0UL) time = 1; { double t = (double)time / T8254_REF_CLOCK_HZ; double rate = (double)bytes / t; doubleprintf(" - %lu bytes played in %.3f seconds\n",(unsigned long)bytes,t); doubleprintf(" - Sample rate is %.3fHz\n",rate); } }
void kernel_main(multiboot_info_t *mbi) { _cli(); init_video(); printk("=== Arcanum kernel ===\n"); printk("Chargement de la GDT... "); gdt_init(); __pok(); printk("Chargement de l'IDT... "); idt_init(); pic_init(); _clock = 0; __pok(); printk("Activation des interruptions. \n"); _sti(); for(;;) {} }
/* private */ static void soundblaster_update_wav_dma_position(soundcard_t sc,struct sndsb_ctx *card) { _cli(); sc->wav_state.dma_position = sndsb_read_dma_buffer_position(card); _sti(); }
int disableInts() { int flags = gFlags(); /* Retorna si el I flag está on o no */ _cli(); return (flags & (0x1 << 9)); }
void pulse_width_test() { int fd; unsigned char cc; unsigned int play; unsigned char plan_b=0; unsigned int patience = 10000; _cli(); write_8254_system_timer(0xFFFF); /* BUGFIX: Personal experience tells me BIOSes would fail reading the floppy if the IRQ 0 timer isn't ticking along at 18Hz */ _sti(); fd = open("..\\test1_22.wav",O_RDONLY|O_BINARY); if (fd < 0) fd = open("test1_22.wav",O_RDONLY|O_BINARY); if (fd < 0) { fprintf(stderr,"Cannot open test WAV\n"); return; } lseek(fd,44,SEEK_SET); read(fd,tmp,sizeof(tmp)); for (play=0;play < sizeof(tmp);play++) tmp[play] = (((tmp[play]) * 53) / 255) + 1; /* add "noise" to dither */ close(fd); /* set timer 0 to 54 ticks (1.191MHz / 54 ~ 22050Hz) */ _cli(); t8254_pc_speaker_set_gate(0); write_8254_pc_speaker(1); write_8254_system_timer(54); _sti(); _cli(); { outp(T8254_CONTROL_PORT,(0 << 6) | (0 << 4) | 0); /* latch counter N, counter latch read */ do { if (--patience == 1) break; cc = inp(T8254_TIMER_PORT(0)); inp(T8254_TIMER_PORT(0)); } while (cc < (54/2)); do { if (--patience == 0) break; cc = inp(T8254_TIMER_PORT(0)); inp(T8254_TIMER_PORT(0)); } while (cc >= (54/2)); if (patience <= 2) { write_8254_system_timer(0xFFFF); /* BUGFIX: on very old slow machines, the 54-count tick can easily cause the printf() below to absolutely CRAWL... */ _sti(); fprintf(stderr,"Oops! Either your CPU is too fast or the timer countdown trick doesn't work.\n"); _cli(); write_8254_system_timer(54); plan_b = 1; } } _sti(); while (1) { if (kbhit()) { int c = getch(); if (c == 27) break; } if (plan_b) { /* run with interrupts enabled, use IRQ0 to know when to tick */ _cli(); counter = 0; t8254_pc_speaker_set_gate(3); for (play=0;play < sizeof(tmp);) { outp(T8254_CONTROL_PORT,(2 << 6) | (1 << 4) | (T8254_MODE_0_INT_ON_TERMINAL_COUNT << 1)); /* MODE 0, low byte only, counter 2 */ outp(T8254_TIMER_PORT(2),tmp[play]); _sti(); while (counter == 0); _cli(); play += counter; counter = 0; } _sti(); } else { _cli(); t8254_pc_speaker_set_gate(3); outp(T8254_CONTROL_PORT,(0 << 6) | (0 << 4) | 0); /* latch counter N, counter latch read */ for (play=0;play < sizeof(tmp);play++) { outp(T8254_CONTROL_PORT,(2 << 6) | (1 << 4) | (T8254_MODE_0_INT_ON_TERMINAL_COUNT << 1)); /* MODE 0, low byte only, counter 2 */ outp(T8254_TIMER_PORT(2),tmp[play]); do { cc = inp(T8254_TIMER_PORT(0)); inp(T8254_TIMER_PORT(0)); } while (cc < (54/2)); do { cc = inp(T8254_TIMER_PORT(0)); inp(T8254_TIMER_PORT(0)); } while (cc >= (54/2)); } _sti(); } } t8254_pc_speaker_set_gate(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; }
/* this is used to probe for ports in standard locations, when we really don't know if it's there */ int probe_8250(uint16_t port) { unsigned char ier,dlab1,dlab2,c,fcr; struct info_8250 *inf; if (already_got_8250_port(port)) return 0; if (base_8250_full()) return 0; inf = &info_8250_port[base_8250_ports]; inf->type = TYPE_8250_IS_8250; inf->port = port; inf->irq = -1; if (windows_mode == WINDOWS_NONE || windows_mode == WINDOWS_REAL) { /* in real-mode DOS we can play with the UART to our heart's content. so we play with the * DLAB select and interrupt enable registers to detect the UART in a manner non-destructive * to the hardware state. */ /* there's no way to autodetect the COM port's IRQ, we have to guess */ if (port == 0x3F8 || port == 0x3E8) inf->irq = 4; else if (port == 0x2F8 || port == 0x2E8) inf->irq = 3; /* switch registers 0+1 back to RX/TX and interrupt enable, and then test the Interrupt Enable register */ _cli(); outp(port+3,inp(port+3) & 0x7F); if (inp(port+3) == 0xFF) { _sti(); return 0; } ier = inp(port+1); outp(port+1,0); if (inp(port+1) == 0xFF) { _sti(); return 0; } outp(port+1,ier); if ((inp(port+1) & 0xF) != (ier & 0xF)) { _sti(); return 0; } /* then switch 0+1 to DLAB (divisor registers) and see if values differ from what we read the first time */ outp(port+3,inp(port+3) | 0x80); dlab1 = inp(port+0); dlab2 = inp(port+1); outp(port+0,ier ^ 0xAA); outp(port+1,ier ^ 0x55); if (inp(port+1) == ier || inp(port+0) != (ier ^ 0xAA) || inp(port+1) != (ier ^ 0x55)) { outp(port+0,dlab1); outp(port+1,dlab2); outp(port+3,inp(port+3) & 0x7F); _sti(); return 0; } outp(port+0,dlab1); outp(port+1,dlab2); outp(port+3,inp(port+3) & 0x7F); /* now figure out what type */ fcr = inp(port+2); outp(port+2,0xE7); /* write FCR */ c = inp(port+2); /* read IIR */ if (c & 0x40) { /* if FIFO */ if (c & 0x80) { if (c & 0x20) inf->type = TYPE_8250_IS_16750; else inf->type = TYPE_8250_IS_16550A; } else { inf->type = TYPE_8250_IS_16550; } } else { unsigned char oscratch = inp(port+7); /* no FIFO. try the scratch register */ outp(port+7,0x55); if (inp(port+7) == 0x55) { outp(port+7,0xAA); if (inp(port+7) == 0xAA) { outp(port+7,0x00); if (inp(port+7) == 0x00) { inf->type = TYPE_8250_IS_16450; } } } outp(port+7,oscratch); } outp(port+2,fcr); _sti(); } else { unsigned int i; /* if we were to actually do our self-test in a VM, Windows would mistakingly assume we * were trying to use it and would allocate the port. we're just enumerating at this point. * play it safe and assume it works if the port is listed as one of the BIOS ports. * we also don't use interrupts. */ for (i=0;i < bios_8250_ports && port != get_8250_bios_port(i);) i++; if (i >= bios_8250_ports) return 0; } base_8250_port[base_8250_ports++] = port; return 1; }
qword sys_addTimerEvent(qword timerEventFunc, qword interval, qword rcx, qword r8, qword r9){ _cli(); addTimerListener((timerEventT) timerEventFunc,interval); _sti(); return 0; }
void ess_sc_play_test(void) { unsigned char bytespersample = wav_16bit ? 2 : 1; unsigned long time,bytes,expect,tlen,timeout; unsigned long count; unsigned int pc,c; unsigned long d; uint32_t irqc; if (!sb_card->ess_extensions || sb_card->ess_chipset == 0) return; doubleprintf("ESS688 single cycle DSP playback test (%u bit).\n",wav_16bit?16:8); timeout = T8254_REF_CLOCK_HZ * 2UL; for (count=0;count < 256;count++) { if (count >= 128) expect = 795500UL / (256 - count); else expect = 397700UL / (128 - count); _cli(); if (sb_card->irq >= 8) { p8259_OCW2(8,P8259_OCW2_SPECIFIC_EOI | (sb_card->irq & 7)); p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | 2); } else if (sb_card->irq >= 0) { p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | sb_card->irq); } _sti(); tlen = expect; // 1 sec if (tlen > (sb_card->buffer_size / (unsigned long)bytespersample)) tlen = sb_card->buffer_size / (unsigned long)bytespersample; /* NTS: We ask the card to use demand ISA, 4 bytes at a time. * Behavior observed on real hardware, is that if you set up * DMA this way and then set up a non-auto-init DMA transfer * that isn't a multiple of 4, the DMA will stop short of * the full transfer and the IRQ will never fire. Therefore * the transfer length must be a multiple of 4! */ tlen -= tlen & 3; if (tlen == 0) tlen = 4; sb_card->buffer_dma_started_length = tlen * (unsigned long)bytespersample; sb_card->buffer_dma_started = 0; sndsb_reset_dsp(sb_card); sndsb_write_dsp(sb_card,0xD1); /* speaker on */ sndsb_ess_set_extended_mode(sb_card,1/*enable*/); sndsb_setup_dma(sb_card); irqc = sb_card->irq_counter; { /* ESS 688/1869 chipset specific DSP playback. using this mode bypasses a lot of the Sound Blaster Pro emulation and restrictions and allows us to run up to 48KHz 16-bit stereo */ unsigned short t16; int b; _cli(); /* clear IRQ */ sndsb_interrupt_ack(sb_card,3); b = 0x00; /* DMA disable */ b |= 0x00; /* no auto-init */ b |= 0x00; /* [3]=DMA converter in ADC mode [1]=DMA read for ADC playback mode */ sndsb_ess_write_controller(sb_card,0xB8,b); b = sndsb_ess_read_controller(sb_card,0xA8); b &= ~0xB; /* clear mono/stereo and record monitor (bits 3, 1, and 0) */ b |= 2; /* mono 10=mono 01=stereo */ sndsb_ess_write_controller(sb_card,0xA8,b); /* NTS: The meaning of bits 1:0 in register 0xB9 * * 00 single DMA transfer mode * 01 demand DMA transfer mode, 2 bytes/request * 10 demand DMA transfer mode, 4 bytes/request * 11 reserved * * NOTES on what happens if you set bits 1:0 (DMA transfer type) to the "reserved" 11 value: * * ESS 688 (Sharp laptop) Nothing, apparently. Treated the same as 4 bytes/request * * ESS 1887 (Compaq Presario) Triggers a hardware bug where the chip appears to fetch * 3 bytes per demand transfer but then only handle 1 byte, * which translates to audio playing at 3x the sample rate * it should be. NOT because the DAC is running any faster, * but because the chip is only playing back every 3rd sample! * This play only 3rds behavior is consistent across 8/16-bit * PCM and mono/stereo. */ b = 2; /* demand transfer DMA 4 bytes per request */ sndsb_ess_write_controller(sb_card,0xB9,b); sndsb_ess_write_controller(sb_card,0xA1,count); /* effectively disable the lowpass filter (NTS: 0xFF mutes the audio, apparently) */ sndsb_ess_write_controller(sb_card,0xA2,0xFE); t16 = -(tlen * (uint16_t)bytespersample); /* DMA transfer count reload register value is 2's complement of length */ sndsb_ess_write_controller(sb_card,0xA4,t16); /* DMA transfer count low */ sndsb_ess_write_controller(sb_card,0xA5,t16>>8); /* DMA transfer count high */ b = sndsb_ess_read_controller(sb_card,0xB1); b &= ~0xA0; /* clear compat game IRQ, fifo half-empty IRQs */ b |= 0x50; /* set overflow IRQ, and "no function" */ sndsb_ess_write_controller(sb_card,0xB1,b); b = sndsb_ess_read_controller(sb_card,0xB2); b &= ~0xA0; /* clear compat */ b |= 0x50; /* set DRQ/DACKB inputs for DMA */ sndsb_ess_write_controller(sb_card,0xB2,b); b = 0x51; /* enable FIFO+DMA, reserved, load signal */ b |= wav_16bit ? 0x20 : 0x00; /* signed complement mode or not */ sndsb_ess_write_controller(sb_card,0xB7,b); b = 0x90; /* enable FIFO+DMA, reserved, load signal */ b |= wav_16bit ? 0x20 : 0x00; /* signed complement mode or not */ b |= 0x40; /* [3]=stereo [6]=!stereo */ b |= wav_16bit ? 0x04 : 0x00; /* [2]=16bit */ sndsb_ess_write_controller(sb_card,0xB7,b); b = sndsb_ess_read_controller(sb_card,0xB8); sndsb_ess_write_controller(sb_card,0xB8,b | 1); } _cli(); c = read_8254(T8254_TIMER_INTERRUPT_TICK); bytes = tlen; time = 0; _sti(); while (1) { if (irqc != sb_card->irq_counter) break; _cli(); pc = c; c = read_8254(T8254_TIMER_INTERRUPT_TICK); time += (unsigned long)((pc - c) & 0xFFFFU); /* remember: it counts DOWN. assumes full 16-bit count */ _sti(); if (time >= timeout) goto x_timeout; } x_complete: if (time == 0UL) time = 1; { int b; b = sndsb_ess_read_controller(sb_card,0xB8); if (b != -1) { b &= ~0x01; /* stop DMA */ sndsb_ess_write_controller(sb_card,0xB8,b); } } { double t = (double)time / T8254_REF_CLOCK_HZ; double rate = (double)bytes / t; doubleprintf(" - TC 0x%02lX: expecting %luHz, %lu%c/%.3fs @ %.3fHz\n",count,expect,(unsigned long)bytes,wav_16bit?'w':'b',t,rate); } if (kbhit()) { if (getch() == 27) break; } continue; x_timeout: d = d8237_read_count(sb_card->dma8) / (unsigned long)bytespersample; /* counts DOWNWARD */ if (d > tlen) d = 0; /* terminal count */ d = tlen - d; if (irqc == sb_card->irq_counter && d == 0) bytes = 0; /* nothing happened if no IRQ and counter never changed */ else if (bytes > d) bytes = d; goto x_complete; } _cli(); if (sb_card->irq >= 8) { p8259_OCW2(8,P8259_OCW2_SPECIFIC_EOI | (sb_card->irq & 7)); p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | 2); } else if (sb_card->irq >= 0) { p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | sb_card->irq); } _sti(); sndsb_reset_dsp(sb_card); }
void sb16_sc_play_test(void) { unsigned char bytespersample = wav_16bit ? 2 : 1; unsigned long time,bytes,expect,tlen,timeout; unsigned long count; unsigned int pc,c; unsigned long d; uint32_t irqc; int dma; if (wav_16bit && sb_card->dma16 >= 4) dma = sb_card->dma16; else dma = sb_card->dma8; if (sb_card->dsp_vmaj >= 4) /* Sound Blaster 16 */ { } else if (sb_card->is_gallant_sc6600) /* Reveal SC-4000 / Gallant SC-6600 */ { } else return; doubleprintf("SB16 4.x single cycle DSP playback test (%u bit).\n",wav_16bit?16:8); timeout = T8254_REF_CLOCK_HZ * 2UL; count = 0; do { expect = count; _cli(); if (sb_card->irq >= 8) { p8259_OCW2(8,P8259_OCW2_SPECIFIC_EOI | (sb_card->irq & 7)); p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | 2); } else if (sb_card->irq >= 0) { p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | sb_card->irq); } _sti(); tlen = expect; // 1 sec if (tlen < 4000UL) tlen = 4000UL; if (tlen > (sb_card->buffer_size / (unsigned long)bytespersample)) tlen = sb_card->buffer_size / (unsigned long)bytespersample; sb_card->buffer_dma_started_length = tlen * (unsigned long)bytespersample; sb_card->buffer_dma_started = 0; sndsb_reset_dsp(sb_card); sndsb_write_dsp(sb_card,0xD1); /* speaker on */ sndsb_setup_dma(sb_card); irqc = sb_card->irq_counter; sndsb_write_dsp_outrate(sb_card,count); _cli(); c = read_8254(T8254_TIMER_INTERRUPT_TICK); bytes = tlen; time = 0; _sti(); { unsigned int lv = (unsigned int)(tlen - 1UL); /* NTS: Reveal SC-4000 (Gallant 6600) cards DO support SB16 but only specific commands. * Command 0xC0 is not recognized, but command 0xC6 works. */ if (wav_16bit) { if (sb_card->is_gallant_sc6600) sndsb_write_dsp(sb_card,SNDSB_DSPCMD_SB16_AUTOINIT_DMA_DAC_OUT_16BIT); /* 0xB6 */ else sndsb_write_dsp(sb_card,SNDSB_DSPCMD_SB16_DMA_DAC_OUT_16BIT); /* 0xB0 */ sndsb_write_dsp(sb_card,0x10); /* mode (16-bit signed PCM) */ } else { if (sb_card->is_gallant_sc6600) sndsb_write_dsp(sb_card,SNDSB_DSPCMD_SB16_AUTOINIT_DMA_DAC_OUT_8BIT); /* 0xC6 */ else sndsb_write_dsp(sb_card,SNDSB_DSPCMD_SB16_DMA_DAC_OUT_8BIT); /* 0xC0 */ sndsb_write_dsp(sb_card,0x00); /* mode (8-bit unsigned PCM) */ } sndsb_write_dsp(sb_card,lv); sndsb_write_dsp(sb_card,lv >> 8); } while (1) { if (irqc != sb_card->irq_counter) break; _cli(); pc = c; c = read_8254(T8254_TIMER_INTERRUPT_TICK); time += (unsigned long)((pc - c) & 0xFFFFU); /* remember: it counts DOWN. assumes full 16-bit count */ _sti(); if (time >= timeout) goto x_timeout; } x_complete: if (time == 0UL) time = 1; { double t = (double)time / T8254_REF_CLOCK_HZ; double rate = (double)bytes / t; doubleprintf(" - Rate 0x%04lX: expecting %luHz, %lu%c/%.3fs @ %.3fHz\n",count,expect,(unsigned long)bytes,wav_16bit?'w':'b',t,rate); } if (kbhit()) { if (getch() == 27) break; } count += 0x80; /* count by 128 because enumerating all would take too long */ if (count > 0xFFFFUL) break; continue; x_timeout: d = d8237_read_count(dma) / (unsigned long)bytespersample; /* counts DOWNWARD */ if (d > tlen) d = 0; /* terminal count */ d = tlen - d; if (irqc == sb_card->irq_counter && d == 0) bytes = 0; /* nothing happened if no IRQ and counter never changed */ else if (bytes > d) bytes = d; goto x_complete; } while (1); _cli(); if (sb_card->irq >= 8) { p8259_OCW2(8,P8259_OCW2_SPECIFIC_EOI | (sb_card->irq & 7)); p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | 2); } else if (sb_card->irq >= 0) { p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | sb_card->irq); } _sti(); sndsb_reset_dsp(sb_card); sndsb_write_dsp_outrate(sb_card,8000U); }
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; }
void sb1_sc_play_adpcm2_test(void) { unsigned long time,bytes,expect,tlen,timeout; unsigned int count; unsigned int pc,c; unsigned long d; uint32_t irqc; doubleprintf("SB 1.x ADPCM 2-bit single cycle DSP playback test.\n"); timeout = T8254_REF_CLOCK_HZ * 4UL; for (count=0;count < 256;count++) { expect = 1000000UL / (unsigned long)(256 - count); _cli(); if (sb_card->irq >= 8) { p8259_OCW2(8,P8259_OCW2_SPECIFIC_EOI | (sb_card->irq & 7)); p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | 2); } else if (sb_card->irq >= 0) { p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | sb_card->irq); } _sti(); tlen = (expect / 4UL) + 1; // 1 sec if (tlen > sb_card->buffer_size) tlen = sb_card->buffer_size; sb_card->buffer_dma_started_length = tlen; sb_card->buffer_dma_started = 0; sndsb_reset_dsp(sb_card); sndsb_write_dsp(sb_card,0xD1); /* speaker on */ sndsb_setup_dma(sb_card); irqc = sb_card->irq_counter; sndsb_write_dsp_timeconst(sb_card,count); _cli(); c = read_8254(T8254_TIMER_INTERRUPT_TICK); bytes = tlen; time = 0; _sti(); { unsigned int lv = (unsigned int)(tlen - 1UL); sndsb_write_dsp(sb_card,SNDSB_DSPCMD_DMA_DAC_OUT_ADPCM_2BIT_REF); /* 0x17 */ sndsb_write_dsp(sb_card,lv); sndsb_write_dsp(sb_card,lv >> 8); } while (1) { if (irqc != sb_card->irq_counter) break; _cli(); pc = c; c = read_8254(T8254_TIMER_INTERRUPT_TICK); time += (unsigned long)((pc - c) & 0xFFFFU); /* remember: it counts DOWN. assumes full 16-bit count */ _sti(); if (time >= timeout) goto x_timeout; } x_complete: if (time == 0UL) time = 1; { double t = (double)time / T8254_REF_CLOCK_HZ; double rate = (double)(((bytes - 1UL) * 4UL) + 1UL) / t; /* 4 samples/byte + 1 reference */ doubleprintf(" - TC 0x%02X: expecting %luHz, %lub/%.3fs @ %.3fHz\n",count,expect,(unsigned long)bytes,t,rate); } if (kbhit()) { if (getch() == 27) break; } continue; x_timeout: d = d8237_read_count(sb_card->dma8); /* counts DOWNWARD */ if (d > tlen) d = 0; /* terminal count */ d = tlen - d; if (irqc == sb_card->irq_counter && d == 0) bytes = 0; /* nothing happened if no IRQ and counter never changed */ else if (bytes > d) bytes = d; goto x_complete; } _cli(); if (sb_card->irq >= 8) { p8259_OCW2(8,P8259_OCW2_SPECIFIC_EOI | (sb_card->irq & 7)); p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | 2); } else if (sb_card->irq >= 0) { p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | sb_card->irq); } _sti(); sndsb_write_dsp_timeconst(sb_card,0x83); /* 8000Hz */ sndsb_reset_dsp(sb_card); }
qword sys_removeTimerEvent(qword timerEventFunc, qword rdx, qword rcx, qword r8, qword r9) { _cli(); deleteTimerListener((timerEventT) timerEventFunc); _sti(); return 0; }