int main() { // no se usa idtr, el bootloader de Pure ya lo setea en 0x0 y usa ese set_idt_entry(0x20, 0x08, (uint64_t)&_irq00Handler, 0x8E); set_idt_entry (0x21, 0x08, (uint64_t)&_irq01Handler, 0x8E ); //Chequiar bootloader (idt) //Todas las interrupciones habilitadas. picMasterMask(0xFC); picSlaveMask(0xFF); _sti(); ncPrint("[Finished]"); ncNewline(); while (1) { } return 0; }
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(); }
void restoreInts(int iflag) { /* Activo el iflag si no estab!a activado */ if (iflag) _sti(); return; }
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; }
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)); }
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; }
int main() { setup_IDT_entry(0x20, 0x8,(uint64_t) &_irq00Handler, 0x8E); setup_IDT_entry(0x21, 0x8, (uint64_t)&_irq01Handler, 0x8E); setup_IDT_entry(0x80, 0x8,(uint64_t) &syscallHandler, 0x8E); picMasterMask(0xFC); picSlaveMask(0xFF); _sti(); ncPrint("[Kernel Main]"); ncNewline(); ncPrint(" Sample code module at 0x"); ncPrintHex((uint64_t)sampleCodeModuleAddress); ncNewline(); ncPrint(" Calling the sample code module returned: "); ncPrintHex(((EntryPoint)sampleCodeModuleAddress)()); ncNewline(); ncNewline(); ncPrint(" Sample data module at 0x"); ncPrintHex((uint64_t)sampleDataModuleAddress); ncNewline(); ncPrint(" Sample data module contents: "); ncPrint((char*)sampleDataModuleAddress); ncNewline(); ncPrint("[Finished]"); while(1); ncClear(); return 0; }
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 load_idt() { setup_IDT_entry (0x20, 0x08, (uint64_t)&_irq00Handler, ACS_INT); setup_IDT_entry (0x21, 0x08, (uint64_t)&_irq01Handler, ACS_INT); setup_IDT_entry (0x80, 0x08, (uint64_t)&_syscallHandler, ACS_INT); idtr.base = 0; idtr.base += (uint64_t) &idt; idtr.limit = (uint16_t) sizeof(idt)-1; _lidt(&idtr); //Solo interrupcion de teclado y timer tick habilitadas picMasterMask(0xFC); picSlaveMask(0xFF); _sti(); }
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(;;) {} }
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); }
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); }
VOID int21_service(iregs FAR * r) { COUNT rc = 0, rc1; psp FAR *p = MK_FP(cu_psp, 0); void FAR *FP_DS_DX = MK_FP(r->DS, r->DX); /* this is saved so often, that this saves ~100 bytes */ #define CLEAR_CARRY_FLAG() r->FLAGS &= ~FLG_CARRY #define SET_CARRY_FLAG() r->FLAGS |= FLG_CARRY p->ps_stack = (BYTE FAR *) r; #ifdef DEBUG if (bDumpRegs) { fbcopy((VOID FAR *) user_r, (VOID FAR *) & error_regs, sizeof(iregs)); printf("System call (21h): %02x\n", user_r->AX); dump_regs = TRUE; dump(); } #endif if(r->AH >=0x38 && r->AH <= 0x4F) CLEAR_CARRY_FLAG(); /* Clear carry by default for these functions */ dispatch: /* Check for Ctrl-Break */ switch (r->AH) { default: if (!break_ena) break; case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x08: case 0x09: case 0x0a: case 0x0b: if (control_break()) handle_break(); } /* The dispatch handler */ switch (r->AH) { /* int 21h common error handler */ case 0x64: error_invalid: r->AX = -DE_INVLDFUNC; goto error_out; error_exit: r->AX = -rc; error_out: CritErrCode = r->AX; /* Maybe set */ SET_CARRY_FLAG(); break; /* case 0x00: --> Simulate a DOS-4C-00 */ /* Read Keyboard with Echo */ case 0x01: r->AL = _sti(TRUE); sto(r->AL); break; /* Display Character */ case 0x02: sto(r->DL); break; /* Auxiliary Input */ case 0x03: { COUNT scratch; GenericRead(STDAUX, 1, (BYTE FAR *) & r->AL, (COUNT FAR *) & scratch, TRUE); break; } /* Auxiliary Output */ case 0x04: { COUNT scratch; DosWrite(STDAUX, 1, (BYTE FAR *) & r->DL, (COUNT FAR *) &scratch); break; } /* Print Character */ case 0x05: { COUNT scratch; DosWrite(STDPRN, 1, (BYTE FAR *) & r->DL, (COUNT FAR *) &scratch); break; } /* Direct Console I/O */ case 0x06: if (r->DL != 0xff) sto(r->DL); else if (StdinBusy()) { r->AL = 0x00; r->FLAGS |= FLG_ZERO; } else { r->FLAGS &= ~FLG_ZERO; r->AL = _sti(FALSE); } break; /* Direct Console Input */ case 0x07: r->AL = _sti(FALSE); break; /* Read Keyboard Without Echo */ case 0x08: r->AL = _sti(TRUE); break; /* Display String */ case 0x09: { BYTE FAR * q; q = FP_DS_DX; while (*q != '$') ++q; DosWrite(STDOUT, FP_OFF(q) - FP_OFF(FP_DS_DX), FP_DS_DX, (COUNT FAR *) & UnusedRetVal); } r->AL = '$'; break; /* Buffered Keyboard Input */ case 0x0a: sti_0a((keyboard FAR *) FP_DS_DX); break; /* Check Stdin Status */ case 0x0b: if (StdinBusy()) r->AL = 0x00; else r->AL = 0xFF; break; /* Flush Buffer, Read Keayboard */ case 0x0c: KbdFlush(); switch (r->AL) { case 0x01: case 0x06: case 0x07: case 0x08: case 0x0a: r->AH = r->AL; goto dispatch; default: r->AL = 0x00; break; } break; /* Reset Drive */ case 0x0d: flush(); break; /* Set Default Drive */ case 0x0e: r->AL = DosSelectDrv(r->DL); break; case 0x0f: if (FcbOpen(FP_DS_DX)) r->AL = 0; else r->AL = 0xff; break; case 0x10: if (FcbClose(FP_DS_DX)) r->AL = 0; else r->AL = 0xff; break; case 0x11: if (FcbFindFirst(FP_DS_DX)) r->AL = 0; else r->AL = 0xff; break; case 0x12: if (FcbFindNext(FP_DS_DX)) r->AL = 0; else r->AL = 0xff; break; case 0x13: if (FcbDelete(FP_DS_DX)) r->AL = 0; else r->AL = 0xff; break; case 0x14: { if (FcbRead(FP_DS_DX, &CritErrCode)) r->AL = 0; else r->AL = CritErrCode; break; } case 0x15: { if (FcbWrite(FP_DS_DX, &CritErrCode)) r->AL = 0; else r->AL = CritErrCode; break; } case 0x16: if (FcbCreate(FP_DS_DX)) r->AL = 0; else r->AL = 0xff; break; case 0x17: if (FcbRename(FP_DS_DX)) r->AL = 0; else r->AL = 0xff; break; default: #ifdef DEBUG printf("Unsupported INT21 AH = 0x%x, AL = 0x%x.\n", r->AH, r->AL); #endif /* Fall through. */ /* CP/M compatibility functions */ case 0x18: case 0x1d: case 0x1e: case 0x20: #ifndef TSC case 0x61: #endif case 0x6b: r->AL = 0; break; /* Get Default Drive */ case 0x19: r->AL = default_drive; break; /* Set DTA */ case 0x1a: { psp FAR *p = MK_FP(cu_psp, 0); p->ps_dta = FP_DS_DX; dos_setdta(p->ps_dta); } break; /* Get Default Drive Data */ case 0x1b: { BYTE FAR *p; FatGetDrvData(0, (COUNT FAR *) & r->AX, (COUNT FAR *) & r->CX, (COUNT FAR *) & r->DX, (BYTE FAR **) & p); r->DS = FP_SEG(p); r->BX = FP_OFF(p); } break; /* Get Drive Data */ case 0x1c: { BYTE FAR *p; FatGetDrvData(r->DL, (COUNT FAR *) & r->AX, (COUNT FAR *) & r->CX, (COUNT FAR *) & r->DX, (BYTE FAR **) & p); r->DS = FP_SEG(p); r->BX = FP_OFF(p); } break; /* Get default DPB */ /* case 0x1f: see case 0x32 */ /* Random read using FCB */ case 0x21: { if (FcbRandomIO(FP_DS_DX, &CritErrCode, FcbRead)) r->AL = 0; else r->AL = CritErrCode; break; } /* Random write using FCB */ case 0x22: { if (FcbRandomIO(FP_DS_DX, &CritErrCode, FcbWrite)) r->AL = 0; else r->AL = CritErrCode; break; } /* Get file size in records using FCB */ case 0x23: if (FcbGetFileSize(FP_DS_DX)) r->AL = 0; else r->AL = 0xff; break; /* Set random record field in FCB */ case 0x24: FcbSetRandom(FP_DS_DX); break; /* Set Interrupt Vector */ case 0x25: { VOID(INRPT FAR * p) () = FP_DS_DX; setvec(r->AL, p); } break; /* Dos Create New Psp */ case 0x26: { psp FAR *p = MK_FP(cu_psp, 0); new_psp((psp FAR *) MK_FP(r->DX, 0), p->ps_size); } break; /* Read random record(s) using FCB */ case 0x27: { if (FcbRandomBlockRead(FP_DS_DX, r->CX, &CritErrCode)) r->AL = 0; else r->AL = CritErrCode; break; } /* Write random record(s) using FCB */ case 0x28: { if (FcbRandomBlockWrite(FP_DS_DX, r->CX, &CritErrCode)) r->AL = 0; else r->AL = CritErrCode; break; } /* Parse File Name */ case 0x29: { BYTE FAR *lpFileName; lpFileName = MK_FP(r->DS, r->SI); r->AL = FcbParseFname(r->AL, &lpFileName, MK_FP(r->ES, r->DI)); r->DS = FP_SEG(lpFileName); r->SI = FP_OFF(lpFileName); } break; /* Get Date */ case 0x2a: DosGetDate( (BYTE FAR *) & (r->AL), /* WeekDay */ (BYTE FAR *) & (r->DH), /* Month */ (BYTE FAR *) & (r->DL), /* MonthDay */ (COUNT FAR *) & (r->CX)); /* Year */ break; /* Set Date */ case 0x2b: rc = DosSetDate( (BYTE FAR *) & (r->DH), /* Month */ (BYTE FAR *) & (r->DL), /* MonthDay */ (COUNT FAR *) & (r->CX)); /* Year */ if (rc != SUCCESS) r->AL = 0xff; else r->AL = 0; break; /* Get Time */ case 0x2c: DosGetTime( (BYTE FAR *) & (r->CH), /* Hour */ (BYTE FAR *) & (r->CL), /* Minutes */ (BYTE FAR *) & (r->DH), /* Seconds */ (BYTE FAR *) & (r->DL)); /* Hundredths */ break; /* Set Date */ case 0x2d: rc = DosSetTime( (BYTE FAR *) & (r->CH), /* Hour */ (BYTE FAR *) & (r->CL), /* Minutes */ (BYTE FAR *) & (r->DH), /* Seconds */ (BYTE FAR *) & (r->DL)); /* Hundredths */ if (rc != SUCCESS) r->AL = 0xff; else r->AL = 0; break; /* Set verify flag */ case 0x2e: verify_ena = (r->AL ? TRUE : FALSE); break; /* Get DTA */ case 0x2f: r->ES = FP_SEG(dta); r->BX = FP_OFF(dta); break; /* Get DOS Version */ case 0x30: r->AL = os_major; r->AH = os_minor; r->BH = OEM_ID; r->CH = REVISION_MAJOR; /* JPP */ r->CL = REVISION_MINOR; r->BL = REVISION_SEQ; if (ReturnAnyDosVersionExpected) { /* TE for testing purpose only and NOT to be documented: return programs, who ask for version == XX.YY exactly this XX.YY. this makes most MS programs more happy. */ UBYTE FAR *retp = MK_FP(r->cs, r->ip); if ( retp[0] == 0x3d && /* cmp ax, xxyy */ (retp[3] == 0x75 || retp[3] == 0x74)) /* je/jne error */ { r->AL = retp[1]; r->AH = retp[2]; } else if(retp[0] == 0x86 && /* xchg al,ah */ retp[1] == 0xc4 && retp[2] == 0x3d && /* cmp ax, xxyy */ (retp[5] == 0x75 || retp[5] == 0x74)) /* je/jne error */ { r->AL = retp[4]; r->AH = retp[3]; } } break; /* Keep Program (Terminate and stay resident) */ case 0x31: DosMemChange(cu_psp, r->DX < 6 ? 6 : r->DX, 0); return_mode = 3; return_code = r->AL; tsr = TRUE; return_user(); break; /* Get default BPB */ case 0x1f: /* Get DPB */ case 0x32: /* r->DL is NOT changed by MS 6.22 */ /* INT21/32 is documented to reread the DPB */ { struct dpb FAR *dpb; UCOUNT drv = r->DL; if (drv == 0 || r->AH == 0x1f) drv = default_drive; else drv--; if (drv >= lastdrive) { r->AL = 0xFF; CritErrCode = 0x0f; break; } dpb = CDSp->cds_table[drv].cdsDpb; if (dpb == 0 || CDSp->cds_table[drv].cdsFlags & CDSNETWDRV) { r->AL = 0xFF; CritErrCode = 0x0f; break; } dpb->dpb_flags = M_CHANGED; /* force reread of drive BPB/DPB */ if (media_check(dpb) < 0) { r->AL = 0xff; CritErrCode = 0x0f; break; } r->DS = FP_SEG(dpb); r->BX = FP_OFF(dpb); r->AL = 0; } break; /* case 0x33: see int21_syscall */ /* Get InDOS flag */ case 0x34: { BYTE FAR *p; p = (BYTE FAR *) ((BYTE *) & InDOS); r->ES = FP_SEG(p); r->BX = FP_OFF(p); } break; /* Get Interrupt Vector */ case 0x35: { BYTE FAR *p; p = getvec((COUNT) r->AL); r->ES = FP_SEG(p); r->BX = FP_OFF(p); } break; /* Dos Get Disk Free Space */ case 0x36: DosGetFree( r->DL, (COUNT FAR *) & r->AX, (COUNT FAR *) & r->BX, (COUNT FAR *) & r->CX, (COUNT FAR *) & r->DX); break; /* Undocumented Get/Set Switchar */ case 0x37: switch (r->AL) { /* Get switch character */ case 0x00: r->DL = switchar; r->AL = 0x00; break; /* Set switch character */ case 0x01: switchar = r->DL; r->AL = 0x00; break; default: goto error_invalid; } break; /* Get/Set Country Info */ case 0x38: { UWORD cntry = r->AL; if(cntry == 0) cntry = (UWORD)-1; else if(cntry == 0xff) cntry = r->BX; if (0xffff == r->DX) { /* Set Country Code */ if((rc = DosSetCountry(cntry)) < 0) goto error_invalid; } else { /* Get Country Information */ if((rc = DosGetCountryInformation(cntry, FP_DS_DX)) < 0) goto error_invalid; /* HACK FIXME */ if(cntry == (UWORD)-1) cntry = 1; /* END OF HACK */ r->AX = r->BX = cntry; } } break; /* Dos Create Directory */ case 0x39: rc = DosMkdir((BYTE FAR *) FP_DS_DX); if (rc != SUCCESS) goto error_exit; break; /* Dos Remove Directory */ case 0x3a: rc = DosRmdir((BYTE FAR *) FP_DS_DX); if (rc != SUCCESS) goto error_exit; break; /* Dos Change Directory */ case 0x3b: if ((rc = DosChangeDir((BYTE FAR *) FP_DS_DX)) < 0) goto error_exit; break; /* Dos Create File */ case 0x3c: if ((rc = DosCreat(FP_DS_DX, r->CX)) < 0) goto error_exit; else r->AX = rc; break; /* Dos Open */ case 0x3d: if ((rc = DosOpen(FP_DS_DX, r->AL)) < 0) goto error_exit; else r->AX = rc; break; /* Dos Close */ case 0x3e: if ((rc = DosClose(r->BX)) < 0) goto error_exit; break; /* Dos Read */ case 0x3f: rc1 = DosRead(r->BX, r->CX, FP_DS_DX, (COUNT FAR *) & rc); if (rc != SUCCESS) goto error_exit; else r->AX = rc1; break; /* Dos Write */ case 0x40: rc1 = DosWrite(r->BX, r->CX, FP_DS_DX, (COUNT FAR *) & rc); if (rc != SUCCESS) goto error_exit; else r->AX = rc1; break; /* Dos Delete File */ case 0x41: rc = DosDelete((BYTE FAR *) FP_DS_DX); if (rc < 0) goto error_exit; break; /* Dos Seek */ case 0x42: { ULONG lrc; if ((rc = DosSeek(r->BX, (LONG) ((((LONG) (r->CX)) << 16) + r->DX), r->AL, &lrc)) < 0) goto error_exit; else { r->DX = (lrc >> 16); r->AX = (UWORD)lrc; } } break; /* Get/Set File Attributes */ case 0x43: switch (r->AL) { case 0x00: rc = DosGetFattr((BYTE FAR *) FP_DS_DX); if (rc >= SUCCESS) r->CX = rc; break; case 0x01: rc = DosSetFattr((BYTE FAR *) FP_DS_DX, r->CX); break; default: goto error_invalid; } if (rc < SUCCESS) goto error_exit; break; /* Device I/O Control */ case 0x44: rc = DosDevIOctl(r); if (rc != SUCCESS) goto error_exit; break; /* Duplicate File Handle */ case 0x45: rc = DosDup(r->BX); if (rc < SUCCESS) goto error_exit; else r->AX = rc; break; /* Force Duplicate File Handle */ case 0x46: rc = DosForceDup(r->BX, r->CX); if (rc < SUCCESS) goto error_exit; break; /* Get Current Directory */ case 0x47: if ((rc = DosGetCuDir(r->DL, MK_FP(r->DS, r->SI))) < 0) goto error_exit; else r->AX = 0x0100; /*jpp: from interrupt list */ break; /* Allocate memory */ case 0x48: if ((rc = DosMemAlloc(r->BX, mem_access_mode, &(r->AX), &(r->BX))) < 0) { DosMemLargest(&(r->BX)); goto error_exit; } else ++(r->AX); /* DosMemAlloc() returns seg of MCB rather than data */ break; /* Free memory */ case 0x49: if ((rc = DosMemFree((r->ES) - 1)) < 0) goto error_exit; break; /* Set memory block size */ case 0x4a: { UWORD maxSize; if ((rc = DosMemChange(r->ES, r->BX, &maxSize)) < 0) { if (rc == DE_NOMEM) r->BX = maxSize; #if 0 if (cu_psp == r->ES) { psp FAR *p; p = MK_FP(cu_psp, 0); p->ps_size = r->BX + cu_psp; } #endif goto error_exit; } break; } /* Load and Execute Program */ case 0x4b: break_flg = FALSE; if ((rc = DosExec(r->AL, MK_FP(r->ES, r->BX), FP_DS_DX)) != SUCCESS) goto error_exit; break; /* Terminate Program */ case 0x00: r->AX = 0x4c00; /* End Program */ case 0x4c: if (cu_psp == RootPsp || ((psp FAR *) (MK_FP(cu_psp, 0)))->ps_parent == cu_psp) break; tsr = FALSE; if (ErrorMode) { ErrorMode = FALSE; return_mode = 2; } else if (break_flg) { break_flg = FALSE; return_mode = 1; } else { return_mode = 0; } return_code = r->AL; if (DosMemCheck() != SUCCESS) panic("MCB chain corrupted"); #ifdef TSC StartTrace(); #endif return_user(); break; /* Get Child-program Return Value */ case 0x4d: r->AL = return_code; r->AH = return_mode; break; /* Dos Find First */ case 0x4e: /* dta for this call is set on entry. This */ /* needs to be changed for new versions. */ if ((rc = DosFindFirst((UCOUNT) r->CX, (BYTE FAR *) FP_DS_DX)) < 0) goto error_exit; r->AX = 0; break; /* Dos Find Next */ case 0x4f: /* dta for this call is set on entry. This */ /* needs to be changed for new versions. */ if ((rc = DosFindNext()) < 0) { if (rc == DE_FILENOTFND) rc = DE_NFILES; goto error_exit; } else r->AX = -SUCCESS; break; /* case 0x50: case 0x51: see int21_syscall */ /* ************UNDOCUMENTED************************************* */ /* Get List of Lists */ case 0x52: { BYTE FAR *p; p = (BYTE FAR *) & DPBp; r->ES = FP_SEG(p); r->BX = FP_OFF(p); } break; case 0x53: /* DOS 2+ internal - TRANSLATE BIOS PARAMETER BLOCK TO DRIVE PARAM BLOCK */ bpb_to_dpb((bpb FAR *)MK_FP(r->DS, r->SI), (struct dpb FAR *)MK_FP(r->ES, r->BP)); break; /* Get verify state */ case 0x54: r->AL = (verify_ena ? TRUE : FALSE); break; /* ************UNDOCUMENTED************************************* */ /* Dos Create New Psp & set p_size */ case 0x55: new_psp((psp FAR *) MK_FP(r->DX, 0), r->SI); cu_psp = r->DX; break; /* Dos Rename */ case 0x56: rc = DosRename((BYTE FAR *) FP_DS_DX, (BYTE FAR *) MK_FP(r->ES, r->DI)); if (rc < SUCCESS) goto error_exit; else CLEAR_CARRY_FLAG(); break; /* Get/Set File Date and Time */ case 0x57: CLEAR_CARRY_FLAG(); switch (r->AL) { case 0x00: rc = DosGetFtime( (COUNT) r->BX, /* Handle */ (date FAR *) & r->DX, /* FileDate */ (time FAR *) & r->CX); /* FileTime */ if (rc < SUCCESS) goto error_exit; break; case 0x01: rc = DosSetFtime( (COUNT) r->BX, /* Handle */ (date) r->DX, /* FileDate */ (time) r->CX); /* FileTime */ if (rc < SUCCESS) goto error_exit; break; default: goto error_invalid; } break; /* Get/Set Allocation Strategy */ case 0x58: CLEAR_CARRY_FLAG(); switch (r->AL) { case 0x00: r->AL = mem_access_mode; r->AH = 0; break; case 0x01: { switch (r->BL) { case LAST_FIT: case LAST_FIT_U: case LAST_FIT_UO: case BEST_FIT: case BEST_FIT_U: case BEST_FIT_UO: case FIRST_FIT: case FIRST_FIT_U: case FIRST_FIT_UO: mem_access_mode = r->BL; break; default: goto error_invalid; } } break; case 0x02: r->AL = uppermem_link; break; case 0x03: if (uppermem_root) { DosUmbLink(r->BL); break; } /* else fall through */ default: goto error_invalid; #ifdef DEBUG case 0xff: show_chain(); break; #endif } break; /* Get Extended Error */ case 0x59: r->AX = CritErrCode; r->ES = FP_SEG(CritErrDev); r->DI = FP_OFF(CritErrDev); r->CH = CritErrLocus; r->BH = CritErrClass; r->BL = CritErrAction; CLEAR_CARRY_FLAG(); break; /* Create Temporary File */ case 0x5a: if ((rc = DosMkTmp(FP_DS_DX, r->CX)) < 0) goto error_exit; else { r->AX = rc; CLEAR_CARRY_FLAG(); } break; /* Create New File */ case 0x5b: if (!IsDevice(FP_DS_DX) && (rc = DosOpen(FP_DS_DX, 0)) >= 0) { DosClose(rc); r->AX = 80; goto error_out; } else { if ((rc = DosCreat(FP_DS_DX, r->CX)) < 0) goto error_exit; else { r->AX = rc; CLEAR_CARRY_FLAG(); } } break; /* /// Added for SHARE. - Ron Cemer */ /* Lock/unlock file access */ case 0x5c: if ((rc = DosLockUnlock (r->BX, (((unsigned long)r->CX)<<16)|(((unsigned long)r->DX)&0xffffL), (((unsigned long)r->SI)<<16)|(((unsigned long)r->DI)&0xffffL), ((r->AX & 0xff) != 0))) != 0) goto error_exit; CLEAR_CARRY_FLAG(); break; /* /// End of additions for SHARE. - Ron Cemer */ /* UNDOCUMENTED: server, share.exe and sda function */ case 0x5d: switch (r->AL) { /* Remote Server Call */ case 0x00: { UWORD FAR *x = FP_DS_DX; r->AX = x[0]; r->BX = x[1]; r->CX = x[2]; r->DX = x[3]; r->SI = x[4]; r->DI = x[5]; r->DS = x[6]; r->ES = x[7]; } goto dispatch; case 0x06: r->DS = FP_SEG(internal_data); r->SI = FP_OFF(internal_data); r->CX = swap_always - internal_data; r->DX = swap_indos - internal_data; CLEAR_CARRY_FLAG(); break; case 0x07: case 0x08: case 0x09: rc = -int2f_Remote_call(REM_PRINTREDIR, 0, 0, r->DX, 0, 0, (MK_FP(0, Int21AX))); if (rc != SUCCESS) goto error_exit; CLEAR_CARRY_FLAG(); break; default: goto error_invalid; } break; case 0x5e: CLEAR_CARRY_FLAG(); switch (r->AL) { case 0x00: r->CX = get_machine_name(FP_DS_DX); break; case 0x01: set_machine_name(FP_DS_DX, r->CX); break; default: rc = -int2f_Remote_call(REM_PRINTSET, r->BX, r->CX, r->DX, (MK_FP(r->ES, r->DI)), r->SI, (MK_FP(r->DS, Int21AX))); if (rc != SUCCESS) goto error_exit; r->AX=SUCCESS; break; } break; case 0x5f: CLEAR_CARRY_FLAG(); switch (r->AL) { case 0x07: if (r->DL < lastdrive) { CDSp->cds_table[r->DL].cdsFlags |= 0x100; } break; case 0x08: if (r->DL < lastdrive) { CDSp->cds_table[r->DL].cdsFlags &= ~0x100; } break; default: /* void int_2f_111e_call(iregs FAR *r); int_2f_111e_call(r); break;*/ rc = -int2f_Remote_call(REM_DOREDIRECT, r->BX, r->CX, r->DX, (MK_FP(r->ES, r->DI)), r->SI, (MK_FP(r->DS, Int21AX))); if (rc != SUCCESS) goto error_exit; r->AX=SUCCESS; break; } break; case 0x60: /* TRUENAME */ CLEAR_CARRY_FLAG(); if ((rc = truename(MK_FP(r->DS, r->SI), adjust_far(MK_FP(r->ES, r->DI)), FALSE)) != SUCCESS) goto error_exit; break; #ifdef TSC /* UNDOCUMENTED: no-op */ /* */ /* DOS-C: tsc support */ case 0x61: #ifdef DEBUG switch (r->AL) { case 0x01: bTraceNext = TRUE; break; case 0x02: bDumpRegs = FALSE; break; } #endif r->AL = 0x00; break; #endif /* UNDOCUMENTED: return current psp case 0x62: is in int21_syscall r->BX = cu_psp; break; */ /* UNDOCUMENTED: Double byte and korean tables */ case 0x63: { #define DBLBYTE #ifdef DBLBYTE static char dbcsTable[2] = { 0, 0 }; void FAR *dp = &dbcsTable; r->DS = FP_SEG(dp); r->SI = FP_OFF(dp); r->AL = 0; #else /* not really supported, but will pass. */ r->AL = 0x00; /*jpp: according to interrupt list */ /*Bart: fails for PQDI: use the above again */ #endif break; } /* case 0x64: see above (invalid) */ /* Extended country info */ case 0x65: switch(r->AL) { case 0x20: /* upcase single character */ r->DL = DosUpChar(r->DL); break; case 0x21: /* upcase memory area */ DosUpMem(FP_DS_DX, r->CX); break; case 0x22: /* upcase ASCIZ */ DosUpString(FP_DS_DX); break; case 0xA0: /* upcase single character of filenames */ r->DL = DosUpFChar(r->DL); break; case 0xA1: /* upcase memory area of filenames */ DosUpFMem(FP_DS_DX, r->CX); break; case 0xA2: /* upcase ASCIZ of filenames */ DosUpFString(FP_DS_DX); break; case 0x23: /* check Yes/No response */ r->AX = DosYesNo(r->DL); break; default: if ((rc = DosGetData( r->AL, r->BX, r->DX, r->CX, MK_FP(r->ES, r->DI))) < 0) { #ifdef NLS_DEBUG printf("DosGetData() := %d\n", rc); #endif goto error_exit; } #ifdef NLS_DEBUG printf("DosGetData() returned successfully\n", rc); #endif break; } CLEAR_CARRY_FLAG(); break; /* Code Page functions */ case 0x66: { int rc; switch (r->AL) { case 1: rc = DosGetCodepage(&r->BX, &r->DX); break; case 2: rc = DosSetCodepage(r->BX, r->DX); break; default: goto error_invalid; } if(rc != SUCCESS) goto error_exit; CLEAR_CARRY_FLAG(); break; } /* Set Max file handle count */ case 0x67: if ((rc = SetJFTSize(r->BX)) != SUCCESS) goto error_exit; else CLEAR_CARRY_FLAG(); break; /* Flush file buffer -- COMMIT FILE -- dummy function right now. */ case 0x68: case 0x6a: CLEAR_CARRY_FLAG(); break; /* Get/Set Serial Number */ case 0x69: rc = ( r->BL == 0 ? default_drive : r->BL - 1); if (rc < lastdrive) { UWORD saveCX = r->CX; if (CDSp->cds_table[rc].cdsFlags & CDSNETWDRV) { goto error_invalid; } switch(r->AL){ case 0x00: r->AL = 0x0d; r->CX = 0x0866; rc = DosDevIOctl(r); break; case 0x01: r->AL = 0x0d; r->CX = 0x0846; rc = DosDevIOctl(r); break; } r->CX = saveCX; if (rc != SUCCESS) goto error_exit; CLEAR_CARRY_FLAG(); break; } else r->AL = 0xFF; break; /* case 0x6a: see case 0x68 case 0x6b: dummy func: return AL=0 */ /* Extended Open-Creat, not fully functional. (bits 4,5,6 of BH) */ case 0x6c: { COUNT x = 0; if (r->AL != 0 || r->DH != 0 || (r->DL&0x0f) > 0x2 || (r->DL&0xf0) > 0x10) goto error_invalid; CLEAR_CARRY_FLAG(); if ((rc = DosOpen(MK_FP(r->DS, r->SI), (r->DL&0x0f) == 0x1 ? r->BL : 0)) < 0) { if (r->DL < 0x10) goto error_exit; /* else try to create below */ } else switch (r->DL & 0x0f) { case 0x0: /* fail if file exists */ DosClose(rc); rc = DE_FILEEXISTS; goto error_exit; case 0x1: /* file exists and opened: OK */ r->CX = 0x01; goto break_out; case 0x2: /* file exists: replace/open */ DosClose(rc); x = 1; break; } /* cases 0x00, 0x01 are finished now */ if ((rc = DosCreat(MK_FP(r->DS, r->SI), r->CX)) < 0) goto error_exit; r->CX = x+2; break_out: r->AX = rc; break; } /* case 0x6d and above not implemented : see default; return AL=0 */ } #ifdef DEBUG if (bDumpRegs) { fbcopy((VOID FAR *) user_r, (VOID FAR *) & error_regs, sizeof(iregs)); dump_regs = TRUE; dump(); } #endif }
/* * The `force_binary' parameter is a hack to allow functions 0x01, 0x06, 0x07, * and function 0x40 to use the same code for performing reads, even though the * two classes of functions behave quite differently: 0x01 etc. always do * binary reads, while for 0x40 the type of read (binary/text) depends on what * the SFT says. -- ror4 */ UCOUNT GenericRead(COUNT hndl, UCOUNT n, BYTE FAR * bp, COUNT FAR * err, BOOL force_binary) { sft FAR *s; WORD sys_idx; sfttbl FAR *sp; UCOUNT ReadCount; /* Test that the handle is valid */ if (hndl < 0) { *err = DE_INVLDHNDL; return 0; } /* Get the SFT block that contains the SFT */ if ((s = get_sft(hndl)) == (sft FAR *) - 1) { *err = DE_INVLDHNDL; return 0; } /* If not open or write permission - exit */ if (s->sft_count == 0 || (s->sft_mode & SFT_MWRITE)) { *err = DE_INVLDACC; return 0; } /* * Do remote first or return error. * must have been opened from remote. */ if (s->sft_flags & SFT_FSHARED) { ReadCount = Remote_RW(REM_READ, n, bp, s, err); if (err) { *err = SUCCESS; return ReadCount; } else return 0; } /* Do a device read if device */ if (s->sft_flags & SFT_FDEVICE) { request rq; /* First test for eof and exit */ /* immediately if it is */ if (!(s->sft_flags & SFT_FEOF) || (s->sft_flags & SFT_FNUL)) { s->sft_flags &= ~SFT_FEOF; *err = SUCCESS; return 0; } /* Now handle raw and cooked modes */ if (force_binary || (s->sft_flags & SFT_FBINARY)) { rq.r_length = sizeof(request); rq.r_command = C_INPUT; rq.r_count = n; rq.r_trans = (BYTE FAR *) bp; rq.r_status = 0; execrh((request FAR *) & rq, s->sft_dev); if (rq.r_status & S_ERROR) { char_error(&rq, s->sft_dev); } else { *err = SUCCESS; return rq.r_count; } } else if (s->sft_flags & SFT_FCONIN) { kb_buf.kb_size = LINESIZE - 1; kb_buf.kb_count = 0; sti((keyboard FAR *) & kb_buf); fbcopy((BYTE FAR *) kb_buf.kb_buf, bp, kb_buf.kb_count); *err = SUCCESS; return kb_buf.kb_count; } else { *bp = _sti(); *err = SUCCESS; return 1; } } else /* a block read */ { COUNT rc; ReadCount = readblock(s->sft_status, bp, n, &rc); if (rc != SUCCESS) { *err = rc; return 0; } else { *err = SUCCESS; return ReadCount; } } *err = SUCCESS; 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); }
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; }
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); }
qword sys_addTimerEvent(qword timerEventFunc, qword interval, qword rcx, qword r8, qword r9){ _cli(); addTimerListener((timerEventT) timerEventFunc,interval); _sti(); 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_removeTimerEvent(qword timerEventFunc, qword rdx, qword rcx, qword r8, qword r9) { _cli(); deleteTimerListener((timerEventT) timerEventFunc); _sti(); 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; }
VOID int21_service(iregs FAR * r) { COUNT rc, rc1; ULONG lrc; psp FAR *p = MK_FP(cu_psp, 0); p->ps_stack = (BYTE FAR *) r; #ifdef DEBUG if (bDumpRegs) { fbcopy((VOID FAR *) user_r, (VOID FAR *) & error_regs, sizeof(iregs)); printf("System call (21h): %02x\n", user_r->AX); dump_regs = TRUE; dump(); } #endif dispatch: /* Check for Ctrl-Break */ switch (r->AH) { default: if (!break_ena) break; case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x08: case 0x09: case 0x0a: case 0x0b: if (control_break()) handle_break(); } /* The dispatch handler */ switch (r->AH) { /* int 21h common error handler */ case 0x64: case 0x6b: default: error_invalid: r->AX = -DE_INVLDFUNC; goto error_out; error_exit: r->AX = -rc; error_out: r->FLAGS |= FLG_CARRY; break; #if 0 /* Moved to simulate a 0x4c00 -- 1999/04/21 ska */ /* Terminate Program */ case 0x00: if (cu_psp == RootPsp) break; else if (((psp FAR *) (MK_FP(cu_psp, 0)))->ps_parent == cu_psp) break; tsr = FALSE; return_mode = break_flg ? 1 : 0; return_code = r->AL; if (DosMemCheck() != SUCCESS) panic("MCB chain corrupted"); #ifdef TSC StartTrace(); #endif return_user(); break; #endif /* Read Keyboard with Echo */ case 0x01: Do_DosIdle_loop(); r->AL = _sti(); sto(r->AL); break; /* Display Character */ case 0x02: sto(r->DL); break; /* Auxiliary Input */ case 0x03: r->AL = _sti(); break; /* Auxiliary Output */ case 0x04: sto(r->DL); break; /* Print Character */ case 0x05: sto(r->DL); break; /* Direct Cosole I/O */ case 0x06: if (r->DL != 0xff) sto(r->DL); else if (StdinBusy()) { r->AL = 0x00; r->FLAGS |= FLG_ZERO; } else { r->FLAGS &= ~FLG_ZERO; r->AL = _sti(); } break; /* Direct Console Input */ case 0x07: /* Read Keyboard Without Echo */ case 0x08: Do_DosIdle_loop(); r->AL = _sti(); break; /* Display String */ case 0x09: { static COUNT scratch; BYTE FAR *p = MK_FP(r->DS, r->DX), FAR * q; q = p; while (*q != '$') ++q; DosWrite(STDOUT, q - p, p, (COUNT FAR *) & scratch); } r->AL = '$'; break; /* Buffered Keyboard Input */ case 0x0a: ((keyboard FAR *) MK_FP(r->DS, r->DX))->kb_count = 0; sti((keyboard FAR *) MK_FP(r->DS, r->DX)); ((keyboard FAR *) MK_FP(r->DS, r->DX))->kb_count -= 2; break; /* Check Stdin Status */ case 0x0b: if (StdinBusy()) r->AL = 0xFF; else r->AL = 0x00; break; /* Flush Buffer, Read Keayboard */ case 0x0c: KbdFlush(); switch (r->AL) { case 0x01: case 0x06: case 0x07: case 0x08: case 0x0a: r->AH = r->AL; goto dispatch; default: r->AL = 0x00; break; } break; /* Reset Drive */ case 0x0d: flush(); break; /* Set Default Drive */ case 0x0e: r->AL = DosSelectDrv(r->DL); break; case 0x0f: if (FcbOpen(MK_FP(r->DS, r->DX))) r->AL = 0; else r->AL = 0xff; break; case 0x10: if (FcbClose(MK_FP(r->DS, r->DX))) r->AL = 0; else r->AL = 0xff; break; case 0x11: if (FcbFindFirst(MK_FP(r->DS, r->DX))) r->AL = 0; else r->AL = 0xff; break; case 0x12: if (FcbFindNext(MK_FP(r->DS, r->DX))) r->AL = 0; else r->AL = 0xff; break; case 0x13: if (FcbDelete(MK_FP(r->DS, r->DX))) r->AL = 0; else r->AL = 0xff; break; case 0x14: { COUNT nErrorCode; if (FcbRead(MK_FP(r->DS, r->DX), &nErrorCode)) r->AL = 0; else r->AL = nErrorCode; break; } case 0x15: { COUNT nErrorCode; if (FcbWrite(MK_FP(r->DS, r->DX), &nErrorCode)) r->AL = 0; else r->AL = nErrorCode; break; } case 0x16: if (FcbCreate(MK_FP(r->DS, r->DX))) r->AL = 0; else r->AL = 0xff; break; case 0x17: if (FcbRename(MK_FP(r->DS, r->DX))) r->AL = 0; else r->AL = 0xff; break; /* CP/M compatibility functions */ case 0x18: case 0x1d: case 0x1e: case 0x20: #ifndef TSC case 0x61: #endif r->AL = 0; break; /* Get Default Drive */ case 0x19: r->AL = default_drive; break; /* Set DTA */ case 0x1a: { psp FAR *p = MK_FP(cu_psp, 0); p->ps_dta = MK_FP(r->DS, r->DX); dos_setdta(p->ps_dta); } break; /* Get Default Drive Data */ case 0x1b: { BYTE FAR *p; FatGetDrvData(0, (COUNT FAR *) & r->AX, (COUNT FAR *) & r->CX, (COUNT FAR *) & r->DX, (BYTE FAR **) & p); r->DS = FP_SEG(p); r->BX = FP_OFF(p); } break; /* Get Drive Data */ case 0x1c: { BYTE FAR *p; FatGetDrvData(r->DL, (COUNT FAR *) & r->AX, (COUNT FAR *) & r->CX, (COUNT FAR *) & r->DX, (BYTE FAR **) & p); r->DS = FP_SEG(p); r->BX = FP_OFF(p); } break; /* Get default DPB */ case 0x1f: if (default_drive < lastdrive) { struct dpb FAR *dpb = (struct dpb FAR *)CDSp->cds_table[default_drive].cdsDpb; if (dpb == 0) { r->AL = 0xff; break; } r->DS = FP_SEG(dpb); r->BX = FP_OFF(dpb); r->AL = 0; } else r->AL = 0xff; break; /* Random read using FCB */ case 0x21: { COUNT nErrorCode; if (FcbRandomRead(MK_FP(r->DS, r->DX), &nErrorCode)) r->AL = 0; else r->AL = nErrorCode; break; } /* Random write using FCB */ case 0x22: { COUNT nErrorCode; if (FcbRandomWrite(MK_FP(r->DS, r->DX), &nErrorCode)) r->AL = 0; else r->AL = nErrorCode; break; } /* Get file size in records using FCB */ case 0x23: if (FcbGetFileSize(MK_FP(r->DS, r->DX))) r->AL = 0; else r->AL = 0xff; break; /* Set random record field in FCB */ case 0x24: FcbSetRandom(MK_FP(r->DS, r->DX)); break; /* Set Interrupt Vector */ case 0x25: { VOID(INRPT FAR * p) () = MK_FP(r->DS, r->DX); setvec(r->AL, p); } break; /* Dos Create New Psp */ case 0x26: { psp FAR *p = MK_FP(cu_psp, 0); new_psp((psp FAR *) MK_FP(r->DX, 0), p->ps_size); } break; /* Read random record(s) using FCB */ case 0x27: { COUNT nErrorCode; if (FcbRandomBlockRead(MK_FP(r->DS, r->DX), r->CX, &nErrorCode)) r->AL = 0; else r->AL = nErrorCode; break; } /* Write random record(s) using FCB */ case 0x28: { COUNT nErrorCode; if (FcbRandomBlockWrite(MK_FP(r->DS, r->DX), r->CX, &nErrorCode)) r->AL = 0; else r->AL = nErrorCode; break; } /* Parse File Name */ case 0x29: { BYTE FAR *lpFileName; lpFileName = MK_FP(r->DS, r->SI); r->AL = FcbParseFname(r->AL, &lpFileName, MK_FP(r->ES, r->DI)); r->DS = FP_SEG(lpFileName); r->SI = FP_OFF(lpFileName); } break; /* Get Date */ case 0x2a: DosGetDate( (BYTE FAR *) & (r->AL), /* WeekDay */ (BYTE FAR *) & (r->DH), /* Month */ (BYTE FAR *) & (r->DL), /* MonthDay */ (COUNT FAR *) & (r->CX)); /* Year */ break; /* Set Date */ case 0x2b: rc = DosSetDate( (BYTE FAR *) & (r->DH), /* Month */ (BYTE FAR *) & (r->DL), /* MonthDay */ (COUNT FAR *) & (r->CX)); /* Year */ if (rc != SUCCESS) r->AL = 0xff; else r->AL = 0; break; /* Get Time */ case 0x2c: DosGetTime( (BYTE FAR *) & (r->CH), /* Hour */ (BYTE FAR *) & (r->CL), /* Minutes */ (BYTE FAR *) & (r->DH), /* Seconds */ (BYTE FAR *) & (r->DL)); /* Hundredths */ break; /* Set Date */ case 0x2d: rc = DosSetTime( (BYTE FAR *) & (r->CH), /* Hour */ (BYTE FAR *) & (r->CL), /* Minutes */ (BYTE FAR *) & (r->DH), /* Seconds */ (BYTE FAR *) & (r->DL)); /* Hundredths */ if (rc != SUCCESS) r->AL = 0xff; else r->AL = 0; break; /* Set verify flag */ case 0x2e: verify_ena = (r->AL ? TRUE : FALSE); break; /* Get DTA */ case 0x2f: r->ES = FP_SEG(dta); r->BX = FP_OFF(dta); break; /* Get DOS Version */ case 0x30: r->AL = os_major; r->AH = os_minor; r->BH = OEM_ID; r->CH = REVISION_MAJOR; /* JPP */ r->CL = REVISION_MINOR; r->BL = REVISION_SEQ; break; /* Keep Program (Terminate and stay resident) */ case 0x31: DosMemChange(cu_psp, r->DX < 6 ? 6 : r->DX, 0); return_mode = 3; return_code = r->AL; tsr = TRUE; return_user(); break; /* Get DPB */ case 0x32: if (r->DL < lastdrive) { struct dpb FAR *dpb = CDSp->cds_table[r->DL].cdsDpb; if (dpb == 0) { r->AL = 0xff; break; } r->DS = FP_SEG(dpb); r->BX = FP_OFF(dpb); r->AL = 0; } else r->AL = 0xFF; break; /* Get InDOS flag */ case 0x34: { BYTE FAR *p; p = (BYTE FAR *) ((BYTE *) & InDOS); r->ES = FP_SEG(p); r->BX = FP_OFF(p); } break; /* Get Interrupt Vector */ case 0x35: { BYTE FAR *p; p = getvec((COUNT) r->AL); r->ES = FP_SEG(p); r->BX = FP_OFF(p); } break; /* Dos Get Disk Free Space */ case 0x36: DosGetFree( (COUNT) r->DL, (COUNT FAR *) & r->AX, (COUNT FAR *) & r->BX, (COUNT FAR *) & r->CX, (COUNT FAR *) & r->DX); break; /* Undocumented Get/Set Switchar */ case 0x37: switch (r->AL) { /* Get switch character */ case 0x00: r->DL = switchar; r->AL = 0x00; break; /* Set switch character */ case 0x01: switchar = r->DL; r->AL = 0x00; break; default: goto error_invalid; } break; /* Get/Set Country Info */ case 0x38: { BYTE FAR *lpTable = (BYTE FAR *) MK_FP(r->DS, r->DX); BYTE nRetCode; if (0xffff == r->DX) { r->BX = SetCtryInfo( (UBYTE FAR *) & (r->AL), (UWORD FAR *) & (r->BX), (BYTE FAR *) & lpTable, (UBYTE *) & nRetCode); if (nRetCode != 0) { r->AX = 0xff; r->FLAGS |= FLG_CARRY; } else { r->AX = nRetCode; r->FLAGS &= ~FLG_CARRY; } } else { r->BX = GetCtryInfo(&(r->AL), &(r->BX), lpTable); r->FLAGS &= ~FLG_CARRY; } } break; /* Dos Create Directory */ case 0x39: rc = dos_mkdir((BYTE FAR *) MK_FP(r->DS, r->DX)); if (rc != SUCCESS) goto error_exit; else { r->FLAGS &= ~FLG_CARRY; } break; /* Dos Remove Directory */ case 0x3a: rc = dos_rmdir((BYTE FAR *) MK_FP(r->DS, r->DX)); if (rc != SUCCESS) goto error_exit; else { r->FLAGS &= ~FLG_CARRY; } break; /* Dos Change Directory */ case 0x3b: if ((rc = DosChangeDir((BYTE FAR *) MK_FP(r->DS, r->DX))) < 0) goto error_exit; else { r->FLAGS &= ~FLG_CARRY; } break; /* Dos Create File */ case 0x3c: if ((rc = DosCreat(MK_FP(r->DS, r->DX), r->CX)) < 0) goto error_exit; else { r->AX = rc; r->FLAGS &= ~FLG_CARRY; } break; /* Dos Open */ case 0x3d: if ((rc = DosOpen(MK_FP(r->DS, r->DX), r->AL)) < 0) goto error_exit; else { r->AX = rc; r->FLAGS &= ~FLG_CARRY; } break; /* Dos Close */ case 0x3e: if ((rc = DosClose(r->BX)) < 0) goto error_exit; else r->FLAGS &= ~FLG_CARRY; break; /* Dos Read */ case 0x3f: rc = DosRead(r->BX, r->CX, MK_FP(r->DS, r->DX), (COUNT FAR *) & rc1); if (rc1 != SUCCESS) { r->FLAGS |= FLG_CARRY; r->AX = -rc1; } else { r->FLAGS &= ~FLG_CARRY; r->AX = rc; } break; /* Dos Write */ case 0x40: rc = DosWrite(r->BX, r->CX, MK_FP(r->DS, r->DX), (COUNT FAR *) & rc1); if (rc1 != SUCCESS) { r->FLAGS |= FLG_CARRY; r->AX = -rc1; } else { r->FLAGS &= ~FLG_CARRY; r->AX = rc; } break; /* Dos Delete File */ case 0x41: rc = dos_delete((BYTE FAR *) MK_FP(r->DS, r->DX)); if (rc < 0) { r->FLAGS |= FLG_CARRY; r->AX = -rc1; } else r->FLAGS &= ~FLG_CARRY; break; /* Dos Seek */ case 0x42: if ((rc = DosSeek(r->BX, (LONG) ((((LONG) (r->CX)) << 16) + r->DX), r->AL, &lrc)) < 0) goto error_exit; else { r->DX = (lrc >> 16); r->AX = lrc & 0xffff; r->FLAGS &= ~FLG_CARRY; } break; /* Get/Set File Attributes */ case 0x43: switch (r->AL) { case 0x00: rc = DosGetFattr((BYTE FAR *) MK_FP(r->DS, r->DX), (UWORD FAR *) & r->CX); if (rc < SUCCESS) goto error_exit; else { r->FLAGS &= ~FLG_CARRY; } break; case 0x01: rc = DosSetFattr((BYTE FAR *) MK_FP(r->DS, r->DX), (UWORD FAR *) & r->CX); if (rc != SUCCESS) goto error_exit; else r->FLAGS &= ~FLG_CARRY; break; default: goto error_invalid; } break; /* Device I/O Control */ case 0x44: { rc = DosDevIOctl(r, (COUNT FAR *) & rc1); if (rc1 != SUCCESS) { r->FLAGS |= FLG_CARRY; r->AX = -rc1; } else { r->FLAGS &= ~FLG_CARRY; } } break; /* Duplicate File Handle */ case 0x45: rc = DosDup(r->BX); if (rc < SUCCESS) goto error_exit; else { r->FLAGS &= ~FLG_CARRY; r->AX = rc; } break; /* Force Duplicate File Handle */ case 0x46: rc = DosForceDup(r->BX, r->CX); if (rc < SUCCESS) goto error_exit; else r->FLAGS &= ~FLG_CARRY; break; /* Get Current Directory */ case 0x47: if ((rc = DosGetCuDir(r->DL, MK_FP(r->DS, r->SI))) < 0) goto error_exit; else { r->FLAGS &= ~FLG_CARRY; r->AX = 0x0100; /*jpp: from interrupt list */ } break; /* Allocate memory */ case 0x48: if ((rc = DosMemAlloc(r->BX, mem_access_mode, &(r->AX), &(r->BX))) < 0) { DosMemLargest(&(r->BX)); goto error_exit; } else { ++(r->AX); /* DosMemAlloc() returns seg of MCB rather than data */ r->FLAGS &= ~FLG_CARRY; } break; /* Free memory */ case 0x49: if ((rc = DosMemFree((r->ES) - 1)) < 0) goto error_exit; else r->FLAGS &= ~FLG_CARRY; break; /* Set memory block size */ case 0x4a: { UWORD maxSize; if ((rc = DosMemChange(r->ES, r->BX, &maxSize)) < 0) { if (rc == DE_NOMEM) r->BX = maxSize; #if 0 if (cu_psp == r->ES) { psp FAR *p; p = MK_FP(cu_psp, 0); p->ps_size = r->BX + cu_psp; } #endif goto error_exit; } else r->FLAGS &= ~FLG_CARRY; break; } /* Load and Execute Program */ case 0x4b: break_flg = FALSE; if ((rc = DosExec(r->AL, MK_FP(r->ES, r->BX), MK_FP(r->DS, r->DX))) != SUCCESS) goto error_exit; else r->FLAGS &= ~FLG_CARRY; break; /* Terminate Program */ case 0x00: r->AX = 0x4c00; /* End Program */ case 0x4c: if (cu_psp == RootPsp || ((psp FAR *) (MK_FP(cu_psp, 0)))->ps_parent == cu_psp) break; tsr = FALSE; /* int2f_Remote_call(0x1122, 0, 0, 0, 0, 0, 0); int2f_Remote_call(REM_CLOSEALL, 0, 0, 0, 0, 0, 0); */ if (ErrorMode) { ErrorMode = FALSE; return_mode = 2; } else if (break_flg) { break_flg = FALSE; return_mode = 1; } else { return_mode = 0; } return_code = r->AL; if (DosMemCheck() != SUCCESS) panic("MCB chain corrupted"); #ifdef TSC StartTrace(); #endif return_user(); break; /* Get Child-program Return Value */ case 0x4d: r->AL = return_code; r->AH = return_mode; break; /* Dos Find First */ case 0x4e: { /* dta for this call is set on entry. This */ /* needs to be changed for new versions. */ if ((rc = DosFindFirst((UCOUNT) r->CX, (BYTE FAR *) MK_FP(r->DS, r->DX))) < 0) goto error_exit; else { r->AX = 0; r->FLAGS &= ~FLG_CARRY; } } break; /* Dos Find Next */ case 0x4f: { /* dta for this call is set on entry. This */ /* needs to be changed for new versions. */ if ((rc = DosFindNext()) < 0) { r->AX = -rc; if (r->AX == 2) r->AX = 18; r->FLAGS |= FLG_CARRY; } else { r->FLAGS &= ~FLG_CARRY; } } break; /* ************UNDOCUMENTED************************************* */ /* Get List of Lists */ case 0x52: { BYTE FAR *p; p = (BYTE FAR *) & DPBp; r->ES = FP_SEG(p); r->BX = FP_OFF(p); } break; /* Get verify state */ case 0x54: r->AL = (verify_ena ? TRUE : FALSE); break; /* ************UNDOCUMENTED************************************* */ /* Dos Create New Psp & set p_size */ case 0x55: new_psp((psp FAR *) MK_FP(r->DX, 0), r->SI); break; /* Dos Rename */ case 0x56: rc = dos_rename( (BYTE FAR *) MK_FP(r->DS, r->DX), /* OldName */ (BYTE FAR *) MK_FP(r->ES, r->DI)); /* NewName */ if (rc < SUCCESS) goto error_exit; else { r->FLAGS &= ~FLG_CARRY; } break; /* Get/Set File Date and Time */ case 0x57: switch (r->AL) { case 0x00: rc = DosGetFtime( (COUNT) r->BX, /* Handle */ (date FAR *) & r->DX, /* FileDate */ (time FAR *) & r->CX); /* FileTime */ if (rc < SUCCESS) goto error_exit; else r->FLAGS &= ~FLG_CARRY; break; case 0x01: rc = DosSetFtime( (COUNT) r->BX, /* Handle */ (date FAR *) & r->DX, /* FileDate */ (time FAR *) & r->CX); /* FileTime */ if (rc < SUCCESS) goto error_exit; else r->FLAGS &= ~FLG_CARRY; break; default: goto error_invalid; } break; /* Get/Set Allocation Strategy */ case 0x58: switch (r->AL) { case 0x00: r->AX = mem_access_mode; break; case 0x01: if (((COUNT) r->BX) < 0 || r->BX > 2) goto error_invalid; else { mem_access_mode = r->BX; r->FLAGS &= ~FLG_CARRY; } break; default: goto error_invalid; #ifdef DEBUG case 0xff: show_chain(); break; #endif } break; /* Create Temporary File */ case 0x5a: if ((rc = DosMkTmp(MK_FP(r->DS, r->DX), r->CX)) < 0) goto error_exit; else { r->AX = rc; r->FLAGS &= ~FLG_CARRY; } break; /* Create New File */ case 0x5b: if ((rc = DosOpen(MK_FP(r->DS, r->DX), 0)) >= 0) { DosClose(rc); r->AX = 80; r->FLAGS |= FLG_CARRY; } else { if ((rc = DosCreat(MK_FP(r->DS, r->DX), r->CX)) < 0) goto error_exit; else { r->AX = rc; r->FLAGS &= ~FLG_CARRY; } } break; /* UNDOCUMENTED: server, share.exe and sda function */ case 0x5d: switch (r->AL) { /* Remote Server Call */ case 0x00: { UWORD FAR *x = MK_FP(r->DS, r->DX); r->AX = x[0]; r->BX = x[1]; r->CX = x[2]; r->DX = x[3]; r->SI = x[4]; r->DI = x[5]; r->DS = x[6]; r->ES = x[7]; } goto dispatch; case 0x06: r->DS = FP_SEG(internal_data); r->SI = FP_OFF(internal_data); r->CX = swap_always - internal_data; r->DX = swap_indos - internal_data; r->FLAGS &= ~FLG_CARRY; break; case 0x07: case 0x08: case 0x09: int2f_Remote_call(REM_PRINTREDIR, 0, 0, r->DX, 0, 0, (MK_FP(0, Int21AX))); break; default: goto error_invalid; } break; case 0x5e: switch (r->AL) { case 0x00: r->CX = get_machine_name(MK_FP(r->DS, r->DX)); break; case 0x01: set_machine_name(MK_FP(r->DS, r->DX), r->CX); break; default: int2f_Remote_call(REM_PRINTSET, r->BX, r->CX, r->DX, (MK_FP(r->ES, r->DI)), r->SI, (MK_FP(r->DS, Int21AX))); break; } break; case 0x5f: switch (r->AL) { case 0x07: CDSp->cds_table[r->DL].cdsFlags |= 0x100; break; case 0x08: CDSp->cds_table[r->DL].cdsFlags &= ~0x100; break; default: int2f_Remote_call(REM_DOREDIRECT, r->BX, r->CX, r->DX, (MK_FP(r->ES, r->DI)), r->SI, (MK_FP(r->DS, Int21AX))); break; } break; case 0x60: /* TRUENAME */ if ((rc = truename(MK_FP(r->DS, r->SI), adjust_far(MK_FP(r->ES, r->DI)), TRUE)) != SUCCESS) goto error_exit; else { r->FLAGS &= ~FLG_CARRY; } break; #ifdef TSC /* UNDOCUMENTED: no-op */ /* */ /* DOS-C: tsc support */ case 0x61: #ifdef DEBUG switch (r->AL) { case 0x01: bTraceNext = TRUE; break; case 0x02: bDumpRegs = FALSE; break; } #endif r->AL = 0x00; break; #endif /* UNDOCUMENTED: return current psp */ case 0x62: r->BX = cu_psp; break; /* UNDOCUMENTED: Double byte and korean tables */ case 0x63: { #ifdef DBLBYTE static char dbcsTable[2] = { 0, 0 }; void FAR *dp = &dbcsTable; r->DS = FP_SEG(dp); r->SI = FP_OFF(dp); r->AL = 0; #else /* not really supported, but will pass. */ r->AL = 0x00; /*jpp: according to interrupt list */ #endif break; } /* Extended country info */ case 0x65: if (r->AL <= 0x7) { if (ExtCtryInfo( r->AL, r->BX, r->CX, MK_FP(r->ES, r->DI))) r->FLAGS &= ~FLG_CARRY; else goto error_invalid; } else if ((r->AL >= 0x20) && (r->AL <= 0x22)) { switch (r->AL) { case 0x20: r->DL = upChar(r->DL); goto okay; case 0x21: upMem( MK_FP(r->DS, r->DX), r->CX); goto okay; case 0x22: upString(MK_FP(r->DS, r->DX)); okay: r->FLAGS &= ~FLG_CARRY; break; case 0x23: r->AX = yesNo(r->DL); goto okay; default: goto error_invalid; } } else r->FLAGS |= FLG_CARRY; break; /* Code Page functions */ case 0x66: switch (r->AL) { case 1: GetGlblCodePage( (UWORD FAR *) & (r->BX), (UWORD FAR *) & (r->DX)); goto okay_66; case 2: SetGlblCodePage( (UWORD FAR *) & (r->BX), (UWORD FAR *) & (r->DX)); okay_66: r->FLAGS &= ~FLG_CARRY; break; default: goto error_invalid; } break; /* Set Max file handle count */ case 0x67: if ((rc = SetJFTSize(r->BX)) != SUCCESS) goto error_exit; else { r->FLAGS &= ~FLG_CARRY; } break; /* Flush file buffer -- dummy function right now. */ case 0x68: r->FLAGS &= ~FLG_CARRY; break; } #ifdef DEBUG if (bDumpRegs) { fbcopy((VOID FAR *) user_r, (VOID FAR *) & error_regs, sizeof(iregs)); dump_regs = TRUE; dump(); } #endif }
//----------------------------------------------------------------------------- // // 命令コマンドを解釈してバイナリに変換 // //----------------------------------------------------------------------------- bool encode(char* instName, char* buffer, map<uint32_t, string>& labelNames, uint32_t currentLine, uint32_t& code, bool& useLabel) { uint32_t rs = 0; uint32_t rt = 0; uint32_t rd = 0; uint32_t imm = 0; double d = 0; char label[MAX_LINE_SIZE]; char dummy[MAX_LINE_SIZE]; if (eq(instName, "add")) { int n = sscanf(buffer, formRRR, dummy, &rd, &rs, &rt); if (n == 4) { code = _add(rs, rt, rd); return true; } } if (eq(instName, "sub")) { int n = sscanf(buffer, formRRR, dummy, &rd, &rs, &rt); if (n == 4) { code = _sub(rs, rt, rd); return true; } } if (eq(instName, "mul")) { int n = sscanf(buffer, formRRR, dummy, &rd, &rs, &rt); if (n == 4) { code = _mul(rs, rt, rd); return true; } } if (eq(instName, "and")) { int n = sscanf(buffer, formRRR, dummy, &rd, &rs, &rt); if (n == 4) { code = _and(rs, rt, rd); return true; } } if (eq(instName, "or")) { int n = sscanf(buffer, formRRR, dummy, &rd, &rs, &rt); if (n == 4) { code = _or(rs, rt, rd); return true; } } if (eq(instName, "nor")) { int n = sscanf(buffer, formRRR, dummy, &rd, &rs, &rt); if (n == 4) { code = _nor(rs, rt, rd); return true; } } if (eq(instName, "xor")) { int n = sscanf(buffer, formRRR, dummy, &rd, &rs, &rt); if (n == 4) { code = _xor(rs, rt, rd); return true; } } if (eq(instName, "addi")) { int n = sscanf(buffer, formRRI, dummy, &rt, &rs, &imm); if (n == 4) { code = _addi(rs, rt, imm); return true; } } if (eq(instName, "subi")) { int n = sscanf(buffer, formRRI, dummy, &rt, &rs, &imm); if (n == 4) { code = _subi(rs, rt, imm); return true; } } if (eq(instName, "muli")) { int n = sscanf(buffer, formRRI, dummy, &rt, &rs, &imm); if (n == 4) { code = _muli(rs, rt, imm); return true; } } if (eq(instName, "slli")) { int n = sscanf(buffer, formRRI, dummy, &rt, &rs, &imm); if (n == 4) { code = _slli(rs, rt, imm); return true; } } if (eq(instName, "srai")) { int n = sscanf(buffer, formRRI, dummy, &rt, &rs, &imm); if (n == 4) { code = _srai(rs, rt, imm); return true; } } if (eq(instName, "andi")) { int n = sscanf(buffer, formRRI, dummy, &rt, &rs, &imm); if (n == 4) { code = _andi(rs, rt, imm); return true; } } if (eq(instName, "ori")) { int n = sscanf(buffer, formRRI, dummy, &rt, &rs, &imm); if (n == 4) { code = _ori(rs, rt, imm); return true; } } if (eq(instName, "nori")) { int n = sscanf(buffer, formRRI, dummy, &rt, &rs, &imm); if (n == 4) { code = _nori(rs, rt, imm); return true; } } if (eq(instName, "xori")) { int n = sscanf(buffer, formRRI, dummy, &rt, &rs, &imm); if (n == 4) { code = _xori(rs, rt, imm); return true; } } if (eq(instName, "fadd")) { int n = sscanf(buffer, formFFF, dummy, &rd, &rs, &rt); if (n == 4) { code = _fadd(rs, rt, rd); return true; } } if (eq(instName, "fsub")) { int n = sscanf(buffer, formFFF, dummy, &rd, &rs, &rt); if (n == 4) { code = _fsub(rs, rt, rd); return true; } } if (eq(instName, "fmul")) { int n = sscanf(buffer, formFFF, dummy, &rd, &rs, &rt); if (n == 4) { code = _fmul(rs, rt, rd); return true; } } if (eq(instName, "fmuln")) { int n = sscanf(buffer, formFFF, dummy, &rd, &rs, &rt); if (n == 4) { code = _fmuln(rs, rt, rd); return true; } } if (eq(instName, "finv")) { int n = sscanf(buffer, formFF, dummy, &rd, &rs); if (n == 3) { code = _finv(rs, rt, rd); return true; } } if (eq(instName, "fsqrt")) { int n = sscanf(buffer, formFF, dummy, &rd, &rs); if (n == 3) { code = _fsqrt(rs, rt, rd); return true; } } if (eq(instName, "fmov")) { int n = sscanf(buffer, formFF, dummy, &rd, &rs); if (n == 3) { code = _fmov(rs, rt, rd); return true; } } if (eq(instName, "fneg")) { int n = sscanf(buffer, formFF, dummy, &rd, &rs); if (n == 3) { code = _fneg(rs, rt, rd); return true; } } if (eq(instName, "imovf")) { int n = sscanf(buffer, formFR, dummy, &rt, &rs); if (n == 3) { code = _imovf(rs, rt, rd); return true; } } if (eq(instName, "fmovi")) { int n = sscanf(buffer, formRF, dummy, &rt, &rs); if (n == 3) { code = _fmovi(rs, rt, rd); return true; } } // to use ALU if (eq(instName, "mvlo")) { int n = sscanf(buffer, formRI, dummy, &rt, &imm); if (n == 3) { code = _mvlo(rt, rt, imm); return true; } } if (eq(instName, "mvhi")) { int n = sscanf(buffer, formRI, dummy, &rt, &imm); if (n == 3) { code = _mvhi(rt, rt, imm); return true; } } if (eq(instName, "fmvlo")) { int n = sscanf(buffer, formFI, dummy, &rt, &imm); if (n == 3) { code = _fmvlo(rt, rt, imm); return true; } } if (eq(instName, "fmvhi")) { int n = sscanf(buffer, formFI, dummy, &rt, &imm); if (n == 3) { code = _fmvhi(rt, rt, imm); return true; } } if (eq(instName, "j")) { int n = sscanf(buffer, formL, dummy, label); if (n == 2) { labelNames[currentLine] = string(label); // cerr << "assigned (" << currentLine << ", " << string(label) << ") in labelNames" << endl; useLabel = true; code = _j(0); return true; } } if (eq(instName, "beq")) { int n = sscanf(buffer, formRRL, dummy, &rs, &rt, label); if (n == 4) { labelNames[currentLine] = string(label); // cerr << "assigned (" << currentLine << ", " << string(label) << ") in labelNames" << endl; useLabel = true; code = _beq(rs, rt, imm); return true; } } if (eq(instName, "blt")) { int n = sscanf(buffer, formRRL, dummy, &rs, &rt, label); if (n == 4) { labelNames[currentLine] = string(label); // cerr << "assigned (" << currentLine << ", " << string(label) << ") in labelNames" << endl; useLabel = true; code = _blt(rs, rt, imm); return true; } } if (eq(instName, "ble")) { int n = sscanf(buffer, formRRL, dummy, &rs, &rt, label); if (n == 4) { labelNames[currentLine] = string(label); // cerr << "assigned (" << currentLine << ", " << string(label) << ") in labelNames" << endl; useLabel = true; code = _ble(rs, rt, imm); return true; } } if (eq(instName, "fbeq")) { int n = sscanf(buffer, formFFL, dummy, &rs, &rt, label); if (n == 4) { labelNames[currentLine] = string(label); // cerr << "assigned (" << currentLine << ", " << string(label) << ") in labelNames" << endl; useLabel = true; code = _fbeq(rs, rt, imm); return true; } } if (eq(instName, "fblt")) { int n = sscanf(buffer, formFFL, dummy, &rs, &rt, label); if (n == 4) { labelNames[currentLine] = string(label); // cerr << "assigned (" << currentLine << ", " << string(label) << ") in labelNames" << endl; useLabel = true; code = _fblt(rs, rt, imm); return true; } } if (eq(instName, "fble")) { int n = sscanf(buffer, formFFL, dummy, &rs, &rt, label); if (n == 4) { labelNames[currentLine] = string(label); // cerr << "assigned (" << currentLine << ", " << string(label) << ") in labelNames" << endl; useLabel = true; code = _fble(rs, rt, imm); return true; } } if (eq(instName, "jr")) { int n = sscanf(buffer, formR, dummy, &rs); if (n == 2) { code = _jr(rs, rt, rd); return true; } } if (eq(instName, "call")) { int n = sscanf(buffer, formL, dummy, label); if (n == 2) { labelNames[currentLine] = string(label); // cerr << "assigned (" << currentLine << ", " << string(label) << ") in labelNames" << endl; useLabel = true; code = _call(0); return true; } } if (eq(instName, "callr")) { int n = sscanf(buffer, formR, dummy, &rs); if (n == 2) { code = _callr(rs, rt, rd); return true; } } if (eq(instName, "return")) { int n = sscanf(buffer, form, dummy); if (n == 1) { code = _return(rs, rt, rd); return true; } } if (eq(instName, "ldr")) { int n = sscanf(buffer, formRRR, dummy, &rd, &rs, &rt); if (n == 4) { code = _ldr(rs, rt, rd); return true; } } if (eq(instName, "fldr")) { int n = sscanf(buffer, formFRR, dummy, &rd, &rs, &rt); if (n == 4) { code = _fldr(rs, rt, rd); return true; } } if (eq(instName, "sti")) { int n = sscanf(buffer, formRRI, dummy, &rt, &rs, &imm); if (n == 4) { code = _sti(rs, rt, imm); return true; } } if (eq(instName, "ldi")) { int n = sscanf(buffer, formRRI, dummy, &rt, &rs, &imm); if (n == 4) { code = _ldi(rs, rt, imm); return true; } } if (eq(instName, "fsti")) { int n = sscanf(buffer, formFRI, dummy, &rt, &rs, &imm); if (n == 4) { code = _fsti(rs, rt, imm); return true; } } if (eq(instName, "fldi")) { int n = sscanf(buffer, formFRI, dummy, &rt, &rs, &imm); if (n == 4) { code = _fldi(rs, rt, imm); return true; } } if (eq(instName, "inputb")) { int n = sscanf(buffer, formR, dummy, &rt); if (n == 2) { code = _inputb(rs, rt, rd); return true; } } if (eq(instName, "outputb")) { int n = sscanf(buffer, formR, dummy, &rt); if (n == 2) { code = _outputb(rs, rt, rd); return true; } } if (eq(instName, "halt")) { int n = sscanf(buffer, form, dummy); if (n == 1) { code = _halt(rs, rt, rd); return true; } } if (eq(instName, "dump")) { int n = sscanf(buffer, form, dummy); if (n == 1) { code = _dump(rs, rt, rd); return true; } } return false; }
/* 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(); }