Please consider a donation to the Higher Intellect project. See https://preterhuman.net/donate.php or the Donate to Higher Intellect page for more info. |
Difference between revisions of "CTV-MOD.ASM"
Jump to navigation
Jump to search
(Created page with "<pre> z PUBLIC _io_addx, _intr_num, _voice_status PUBLIC _ctv_detect, _ctv_speaker, _ctv_output, PUBLIC _ctv_halt PUBLIC _ctv_pa...") |
|||
Line 1: | Line 1: | ||
<pre> | <pre> | ||
− | + | PUBLIC _io_addx, _intr_num, _voice_status | |
PUBLIC _ctv_detect, _ctv_speaker, _ctv_output, | PUBLIC _ctv_detect, _ctv_speaker, _ctv_output, | ||
PUBLIC _ctv_halt | PUBLIC _ctv_halt |
Latest revision as of 11:46, 23 July 2020
PUBLIC _io_addx, _intr_num, _voice_status PUBLIC _ctv_detect, _ctv_speaker, _ctv_output, PUBLIC _ctv_halt PUBLIC _ctv_pause, _ctv_continue, _ctv_uninstall PUBLIC _ctv_card_here WAIT_TIME EQU 0200H DMA_VOICE_IN EQU 45H DMA_VOICE_OUT EQU 49H DSP_ID_CMD EQU 0E0H DSP_VER_CMD EQU 0E1H DSP_VI8_CMD EQU 24H DSP_VO8_CMD EQU 14H DSP_VO2_CMD EQU 17H DSP_VO4_CMD EQU 75H DSP_VO25_CMD EQU 77H DSP_MDAC1_CMD EQU 61H DSP_MDAC2_CMD EQU 62H DSP_MDAC3_CMD EQU 63H DSP_MDAC4_CMD EQU 64H DSP_MDAC5_CMD EQU 65H DSP_MDAC6_CMD EQU 66H DSP_MDAC7_CMD EQU 67H DSP_TIME_CMD EQU 40H DSP_SILENCE_CMD EQU 80H DSP_PAUSE_DMA_CMD EQU 0D0H DSP_ONSPK_CMD EQU 0D1H DSP_OFFSPK_CMD EQU 0D3H DSP_CONT_DMA_CMD EQU 0D4H DSP_INTRQ_CMD EQU 0F2H CMS_TEST_CODE EQU 0C6H RESET_TEST_CODE EQU 0AAH CMS_EXIST EQU 1 FM_MUSIC_EXIST EQU 2 CTV_VOICE_EXIST EQU 4 FM_WAIT_TIME EQU 40H DOSSEG .MODEL SMALL .DATA _io_addx DW 220H _intr_num DB 0 _voice_status DW 0 org_int_addx LABEL DWORD org_int2_addx LABEL DWORD org_int2_off dw ? org_int2_seg dw ? org_int3_addx LABEL DWORD org_int3_off dw ? org_int3_seg dw ? org_int5_addx LABEL DWORD org_int5_off dw ? org_int5_seg dw ? org_int7_addx LABEL DWORD org_int7_off dw ? org_int7_seg dw ? ;--------------------- ; DMA DATA | ;--------------------- dma_current_page db ? dma_current_addx dw ? dma_current_count dw ? page_to_dma db ? len_l_to_dma dw ? len_h_to_dma dw ? last_dma_offset dw ? .CODE write_dsp_time PROC push cx mov cx,WAIT_TIME mov ah,al wdt10: in al,dx or al,al jns wdt20 loop wdt10 stc jmp short wdt90 wdt20: mov al,ah out dx,al clc wdt90: pop cx ret write_dsp_time ENDP read_dsp_time PROC push cx push dx mov dx,_io_addx add dl,0eh mov cx,WAIT_TIME rdt10: in al,dx or al,al js rdt20 loop rdt10 stc jmp short rdt90 rdt20: sub dl,4 in al,dx clc rdt90: pop dx pop cx ret read_dsp_time ENDP write_dsp PROC mov ah,al mov al,0f0h wd10: in al,dx or al,al js wd10 mov al,ah out dx,al ret write_dsp ENDP read_dsp PROC push dx mov dx,_io_addx add dl,0eh sub al,al rd10: in al,dx or al,al jns rd10 sub dl,4 in al,dx pop dx ret read_dsp ENDP reset_dsp PROC mov dx,_io_addx add dl,6 mov al,1 out dx,al in al,dx rdsp05: inc al jnz rdsp05 out dx,al mov cl,20h rdsp10: call read_dsp_time cmp al,0aah je rdsp20 dec cl jnz rdsp10 mov ax,2 jmp short rdsp90 rdsp20: sub ax,ax rdsp90: or ax,ax ret reset_dsp ENDP verify_io_chk PROC mov bx,2 mov al,DSP_ID_CMD mov dx,_io_addx add dx,0ch call write_dsp_time jc vio90 mov al,0aah call write_dsp_time jc vio90 call read_dsp_time jc vio90 cmp al,055h jne vio90 sub bx,bx vio90: mov ax,bx or ax,ax ret verify_io_chk ENDP verify_intr PROC mov al,2 mov dx,offset dummy_dma_int2 mov bx,offset dgroup:org_int2_addx call setup_interrupt mov al,3 mov dx,offset dummy_dma_int3 mov bx,offset dgroup:org_int3_addx call setup_interrupt mov al,5 mov dx,offset dummy_dma_int5 mov bx,offset dgroup:org_int5_addx call setup_interrupt mov al,7 mov dx,offset dummy_dma_int7 mov bx,offset dgroup:org_int7_addx call setup_interrupt MOV _intr_num,0 mov dx,_io_addx add dx,0ch mov al,DSP_INTRQ_CMD call write_dsp in al,21h push ax and al,01010011b out 21h,al sub ax,ax mov cx,WAIT_TIME*4 vi10: cmp _intr_num,0 jnz vi90 loop vi10 mov ax,3 vi90: pop bx push ax mov al,bl out 21h,al mov al,2 mov bx,offset dgroup:org_int2_addx call restore_interrupt mov al,3 mov bx,offset dgroup:org_int3_addx call restore_interrupt mov al,5 mov bx,offset dgroup:org_int5_addx call restore_interrupt mov al,7 mov bx,offset dgroup:org_int7_addx call restore_interrupt pop ax or ax,ax ret verify_intr ENDP chk_dsp_version PROC mov al,DSP_VER_CMD mov dx,_io_addx add dl,0ch call write_dsp call read_dsp mov ah,al call read_dsp mov bx,1 cmp ax,101h jb cdv90 sub bx,bx cdv90: mov ax,bx or ax,ax ret chk_dsp_version ENDP pause_dsp_dma PROC pushf mov ah,DSP_PAUSE_DMA_CMD mov bx,offset dgroup:_voice_status sub cx,cx mov dx,_io_addx add dl,0ch pdd10: sti ; ENABLE INTR. FOR VOICE-OUT INTR cmp cx,[bx] ; TO UPDATE VOICE_STATUS je pdd90 cli ; DISABLE INTR. FOR FOLLOWING CHECK in al,dx ; WHICH IS TIMING CRITICAL or al,al jns pdd10 ; WAIT FOR dsp NOT READY pdd20: in al,dx or al,al js pdd20 ; WAIT FOR dsp READY mov al,ah out dx,al ; WRITE PAUSE DMA IMMEDIATELY pdd90: popf ret pause_dsp_dma ENDP ;-------------------------------------------- ; entry: DH = dma mode : ; DL = page : ; AX = current addx : ; CX = current count : ;-------------------------------------------- DMA_ADDX_REG EQU 02H DMA_COUNT_REG EQU 03H DMA_MASK_REG EQU 0AH DMA_MODE_REG EQU 0BH DMA_FF_REG EQU 0CH DMA_PAGE_REG EQU 83H prog_dma PROC push bx mov bx,ax mov al,5 out DMA_MASK_REG,al sub al,al out DMA_FF_REG,al mov al,dh out DMA_MODE_REG,al mov al,bl out DMA_ADDX_REG,al mov al,bh out DMA_ADDX_REG,al mov al,cl out DMA_COUNT_REG,al mov al,ch out DMA_COUNT_REG,al mov al,dl out DMA_PAGE_REG,al mov al,1 out DMA_MASK_REG,al pop bx ret prog_dma ENDP calc_20bit_addx PROC push cx mov cl,4 rol dx,cl mov cx,dx and dx,0fh and cx,0fff0h add ax,cx adc dx,0 pop cx ret calc_20bit_addx ENDP ;------------------------------------------------- ; entry: AL = INTERRUPT NUM | ; DX = new vector ofs, seg is alway CS | ; BX = offset of store buffer : ;------------------------------------------------- setup_interrupt PROC pushf push bx push cx push dx cli mov cl,al ; PRESERVE INTERRUPT NUMBER FOR USE add al,8 ; CALCULATE INTERRUPT VECTOR ADDX cbw shl al,1 shl al,1 mov di,ax push es ; SETUP AND PRESERVE INTERRUPT sub ax,ax mov es,ax mov ax,es:[di] mov [bx],ax mov es:[di],dx mov ax,es:[di+2] mov [bx+2],ax mov es:[di+2],cs pop es pop dx pop cx pop bx popf ret setup_interrupt ENDP ;------------------------------------------------- ; entry: AL = INTERRUPT NUM | ; BX = offset to stored addx | ;------------------------------------------------- restore_interrupt PROC pushf cli mov cl,al add al,8 ; CALCULATE INTERRUPT VECTOR ADDX cbw shl al,1 shl al,1 mov di,ax push es ; RESTORE INTERRUPT VECTOR sub ax,ax mov es,ax mov ax,[bx] mov es:[di],ax mov ax,[bx+2] mov es:[di+2],ax pop es mov ah,1 shl ah,cl in al,21h or al,ah out 21h,al popf ret restore_interrupt ENDP dummy_dma_int2 PROC FAR push dx mov dl,2 jmp short dummy_dma_isr dummy_dma_int2 ENDP dummy_dma_int3 PROC FAR push dx mov dl,3 jmp short dummy_dma_isr dummy_dma_int3 ENDP dummy_dma_int5 PROC FAR push dx mov dl,5 jmp short dummy_dma_isr dummy_dma_int5 ENDP dummy_dma_int7 PROC FAR push dx mov dl,7 dummy_dma_isr: push ds push ax mov ax,DGROUP mov ds,ax mov _intr_num,dl mov dx,_io_addx add dx,0eh in al,dx mov al,20h out 20h,al pop ax pop ds pop dx iret dummy_dma_int7 ENDP dma_out_intr PROC push ds push es push ax push bx push cx push dx push di push si push bp cld mov ax,DGROUP mov ds,ax mov es,ax mov dx,_io_addx add dl,0eh in al,dx mov ax,len_l_to_dma or ax,ax jnz vo_int10 call end_dma_transfer jmp short vo_int90 vo_int10: call dma_out_transfer vo_int90: mov al,20h out 20h,al pop bp pop si pop di pop dx pop cx pop bx pop ax pop es pop ds iret dma_out_intr ENDP dma_out_transfer PROC mov cx,0ffffh ; GET CURRENT PAGE END ADDRESS cmp page_to_dma,0 ; LAST PAGE TO DMA ? jnz dot10 ; NO, SKIP inc page_to_dma mov cx,last_dma_offset ; GET END ADDX dot10: sub cx,dma_current_addx ; CALCUTATE CURRENT PAGE ADDX mov dma_current_count,cx inc cx jz dot20 sub len_l_to_dma,cx sbb len_h_to_dma,0 jmp short dot30 dot20: dec len_h_to_dma dot30: mov dh,DMA_VOICE_OUT mov dl,dma_current_page mov ax,dma_current_addx mov cx,dma_current_count call prog_dma dec page_to_dma inc dma_current_page mov dma_current_addx,0 mov cx,dma_current_count mov dx,_io_addx add dl,0ch mov al,DSP_VO8_CMD call write_dsp mov al,cl call write_dsp mov al,ch call write_dsp dot90: ret dma_out_transfer ENDP end_dma_transfer PROC mov al,5 out DMA_MASK_REG,al mov cl,_intr_num mov ah,1 shl ah,cl in al,21h or al,ah out 21h,al mov al,_intr_num mov bx,offset DGROUP:org_int_addx call restore_interrupt mov _voice_status,0 mov dx,_io_addx add dl,0eh in al,dx ret end_dma_transfer ENDP ;--------------------------------------- ; WAIT_FM_STATUS : ; entry: AL = status to wait : ; 3 msb is concern : ; exit : AX destroy : ; carry set for fail : ; carry clr for pass : ;--------------------------------------- wait_fm_status PROC push cx push dx mov cx,FM_WAIT_TIME mov ah,al and ah,0e0h ; ONLY 3 MSB ARE fm STATUS mov dx,_io_addx add dl,8 wfs10: in al,dx and al,0e0h cmp ah,al je wfs20 loop wfs10 stc jmp short wfs90 wfs20: clc wfs90: pop dx pop cx ret wait_fm_status ENDP ;--------------------------------------- ; WRITE_FM : ; entry: AH = data value : ; AL = addx value : ; exit : AX destroy : ; DX destroy : ;--------------------------------------- write_fm PROC mov dx,_io_addx add dl,8 out dx,al call fm_delay mov al,ah inc dx out dx,al call fm_delay ret write_fm ENDP fm_delay PROC push ax push dx mov dx,_io_addx add dl,8 in al,dx in al,dx in al,dx in al,dx in al,dx pop dx pop ax ret fm_delay ENDP _ctv_detect PROC push ds push es push di push si mov ax,DGROUP mov ds,ax mov es,ax call reset_dsp jnz id90 call verify_io_chk jnz id90 call chk_dsp_version jnz id90 call verify_intr jnz id90 mov al,1 ; ON SPEAKER call on_off_speaker sub ax,ax id90: pop si pop di pop es pop ds ret _ctv_detect ENDP _ctv_speaker PROC push bp mov bp,sp push ds mov ax,DGROUP mov ds,ax mov ax,[bp+4] call on_off_speaker pop ds pop bp ret _ctv_speaker ENDP on_off_speaker PROC mov dx,_io_addx add dx,0ch mov ah,DSP_ONSPK_CMD or al,al jnz oos10 mov ah,DSP_OFFSPK_CMD oos10: mov al,ah call write_dsp sub ax,ax ; INIDCATE NO ERROR ret on_off_speaker ENDP _ctv_output PROC push bp mov bp,sp push ds push es push di push si mov ax,DGROUP mov ds,ax mov es,ax cmp _voice_status,0 jz ov10 mov ax,1 jmp ov90 ov10: mov _voice_status,1 mov dx,_io_addx add dl,0ch mov dx,0fh ; CALCULATE SAMPLING RATE VALUE FOR mov ax,4240h ; dsp mov cx,[bp+10] div cx mov cl,al neg cl mov dx,_io_addx add dl,0ch mov al,DSP_TIME_CMD call write_dsp mov al,cl call write_dsp mov al,_intr_num mov dx,offset dma_out_intr mov bx,offset DGROUP:org_int_addx call setup_interrupt mov cl,_intr_num mov ah,1 shl ah,cl not ah in al,21h and al,ah out 21h,al mov dx,[bp+6] mov ax,[bp+4] call calc_20bit_addx mov dma_current_page,dl mov dma_current_addx,ax mov cx,[bp+8] mov len_l_to_dma,cx mov len_h_to_dma,0 add ax,[bp+8] adc dl,0 sub ax,1 sbb dl,0 mov last_dma_offset,ax sub dl,dma_current_page mov page_to_dma,dl call dma_out_transfer sub ax,ax ov90: pop si pop di pop es pop ds pop bp ret _ctv_output ENDP _ctv_halt PROC push ds push es push di push si mov ax,DGROUP mov ds,ax mov es,ax mov ax,1 cmp _voice_status,0 jz tvp90 call pause_dsp_dma call end_dma_transfer sub ax,ax tvp90: pop si pop di pop es pop ds ret _ctv_halt ENDP _ctv_pause PROC push ds push es push di push si mov ax,DGROUP mov ds,ax mov es,ax mov ax,1 cmp _voice_status,1 jne pv90 call pause_dsp_dma sub ax,ax pv90: pop si pop di pop es pop ds ret _ctv_pause ENDP _ctv_continue PROC push ds push es push di push si mov ax,DGROUP mov ds,ax mov es,ax mov ax,1 cmp _voice_status,1 jne cv90 mov dx,_io_addx add dl,0ch mov al,DSP_CONT_DMA_CMD call write_dsp sub ax,ax cv90: pop si pop di pop es pop ds ret _ctv_continue ENDP _ctv_uninstall PROC push ds push es push di push si mov ax,DGROUP mov ds,ax mov es,ax cmp _voice_status,0 jz ui90 call pause_dsp_dma call end_dma_transfer ui90: sub al,al call on_off_speaker sub ax,ax pop si pop di pop es pop ds ret _ctv_uninstall ENDP ;----------------------------------------------------------- ; usage: : ; unint ctv_card_here() : ; description: : ; detect the Game Blaster or Sound Blaster Card and : ; the configuration : ; entry: : ; the global i/o addx, ct_io_addx must set to a default : ; value, 2x0H, before call. : ; exit: : ; High Byte = 0 : ; Low Byte format - : ; 0000 0001 : C/MS music exists : ; 0000 0010 : FM music exists : ; 0000 0100 : CTV Voice exists : ;----------------------------------------------------------- _ctv_card_here PROC push ds ; FOR MULTI DATA MODEL, SET ds TO mov ax,DGROUP ; DGROUP segment mov ds,ax sub bx,bx ; ASSUME cREATIVE cARD DOESN'T EXIST, ; return 0 ;----------------------------- ; detect Game Blaster : ;----------------------------- mov dx,_io_addx ; get default i/o addx add dl,6 ; WRITE THE TEST CODE TO mov al,CMS_TEST_CODE ; output port 2x6H out dx,al ; ... sub al,al add dl,4 ; READ THE DATA BACK FROM out dx,al in al,dx ; INPUT PORT 2Xah cmp al,CMS_TEST_CODE ; the same data ? jne card10 ; NO, TRY sOUND bLASTER cARD sub dl,4 ; TO ENSURE, TRY INVERSE DATA mov al,NOT CMS_TEST_CODE ; output port 2x6H out dx,al ; ... sub al,al add dl,4 ; READ THE DATA BACK FROM out dx,al in al,dx ; INPUT PORT 2Xah cmp al,NOT CMS_TEST_CODE ; the same data ? jne card10 ; NO, TRY sOUND bLASTER cARD mov bx,CMS_EXIST jmp short card50 ;-------------------------------------- ; detect the Sound Blaster Card : ;-------------------------------------- card10: call reset_dsp jnz card50 card40: mov dx,_io_addx add dl,0ch mov al,DSP_ID_CMD call write_dsp_time jc card50 mov al,CMS_TEST_CODE call write_dsp_time jc card50 call read_dsp_time jc card50 cmp al,NOT CMS_TEST_CODE jne card50 mov bx,CMS_EXIST + CTV_VOICE_EXIST ;----------------------------- ; detect the FM Music : ;----------------------------- card50: mov ax,0001h ; RESET THE fm CHIP call write_fm mov ax,6004h ; MASK OF TIMER 1 & 2 call write_fm mov ax,8004h ; RESET IRQ AND BOTH TIMER FLAGS call write_fm mov al,0 ; READ FOR 3 MSB CLEAR call wait_fm_status jc card90 mov ax,0ff02h ; WRITE TIMER 1 COUNT call write_fm mov ax,2104h ; START TIMER 1 call write_fm mov al,0c0h ; WAIT FOR IRQ AND TIMER 1 END CALL WAIT_FM_STATUS jc card90 mov ax,6004h ; MASK OF TIMER 1 & 2 call write_fm mov ax,8004h ; RESET IRQ AND BOTH TIMER FLAGS call write_fm add bx,FM_MUSIC_EXIST card90: mov ax,bx pop ds ret _ctv_card_here ENDP END