; THIS ROIUTINE IS THE CONTROL FOR ; THE 8749 ON THE IBM-PC VOICE BOARD. ; IT IS SET FOR 10.000 MHZ. ; PCVCNT.ASM VERSION 2.0 ; APRIL 20,1987 BILL HEIDEMAN ; DECLARED DATA INBFA EQU 20H ;LOWER INPUT BUFFER (32) ; D0=COMMAND ; D1=ADDRESS LOW ; D2=ADDRESS HIGH INBFB EQU 40H ;UPPER INPUT BUFFER (32) COMBUF EQU 60H ;VOICE BOARD BUFFER (8) BUFPTR EQU 68H ;BUFFER POINTER PCMPTR EQU 69H ;PC MEMORY POINTER (2) BGADR EQU 6BH ;BEGINNING ADDR (2) ENADR EQU 6DH ;ENDING ADDR (2) SPEED EQU 6FH ;RECORDING SPEED RECLST EQU 70H ;LAST PC MEM LOCATION (2) ORG 000H RESTRT: JMP MAIN ORG 002H ID: DB 20H ORG 003H EXINT: SEL RB1 ;EXTERNAL INTERRUPT MOV R7,A JMP INTR ORG 007H TMR: RETR ;THIS IS THE INTERRUPT ROUTINE THAT ;DECIPHERES THE COMMUNICATION FROM THE ;IBM-PC. IT IS ON A HARDWARE INTERRUPT. INTR: MOV R1,#COMBUF MOVX A,@R0 ;GET COMMAND MOV R2,A JF1 STPIT ;IF UNIT RUNNING SWAP A ANL A,#0FH ADD A,#INTBL ;FORM PNTR JMPP @A INTBL: DB INTR0 DB INTR1 DB INTR2 DB INTR3 DB INTR4 DB INTR5 DB INTR6 DB INTR7 INTR0: MOV A,R7 RETR INTR1: JMP STRIT ;DO START INTR2: JMP STPIT ;DO STOP INTR3: JMP RECR ;DO RECORD INTR4: JMP PLAY ;DO PLAY INTR5: JMP BGAD ;DO BEGINNING ADDR INTR6: JMP ENAD ;DO ENDING ADDR INTR7: JMP SPED ;DO SPEED ;THIS ROUTINE FORMATS THE START COMMMAND ;(INTR). STRIT: CLR F1 CPL F1 ;SET RUN FLAG MOV R0,#BUFPTR MOV @R0,#0 ;RESET POINTER CALL REST ;RESET VOICE BOARD SEL RB0 MOV A,R6 ;GET RECR FLAG SEL RB1 JZ STR1 ;IF PLAY IS SET MOV R0,#RECLST MOV A,@R0 MOV R0,#PCMPTR MOV @R0,A ;SET UP START OF RECR MOV R0,#RECLST+1 MOV A,@R0 MOV R0,#PCMPTR+1 MOV @R0,A MOV R0,#SPEED MOV A,@R0 MOV @R1,A ;WRITE SPEED INC R1 MOV @R1,#80H ;SET RECORD INC R1 MOV @R1,#10H ;SET RUN MOV A,#3 CALL CMSN ;DO COMMAND SEND JMP INTR0 STR1: MOV R0,#BGADR MOV A,@R0 MOV R0,#PCMPTR ;SET UP PC PTR MOV @R0,A MOV R0,#BGADR+1 MOV A,@R0 MOV R0,#PCMPTR+1 MOV @R0,A MOV R0,#SPEED MOV A,@R0 MOV @R1,A ;WRITE SPEED INC R1 MOV R0,#BGADR CALL ADFR ;DO ADDRESS FORMAT MOV R0,#COMBUF+1 MOV A,@R0 ORL A,#30H ;SET BEGIN CODE MOV @R0,A INC R1 MOV R0,#ENADR CALL ADFR ;DO ADDRESS FORMAT MOV R0,#COMBUF+4 MOV A,@R0 ORL A,#40H ;SET END CODE MOV @R0,A INC R1 MOV @R0,#10H ;SET RUN MOV A,#INBFA ;PRELOAD BUFFER CALL REDI MOV A,#8 CALL CMSN ;DO COMMAND SEND JMP INTR0 ;THIS ROUTINE FORMATS THE STOP COMMAND ;(INTR). STPIT: CLR F1 ;CLEAR RUN CALL REST ;DO RESET JMP INTR0 ;THIS ROUTINE FORMATS THE RECORD COMMAND ;(INTR). RECR: SEL RB0 MOV R6,#0FFH ;SET RECORD SEL RB1 MOV R0,#INBFA MOV @R0,#0 ;SET UP BUFFERS MOV R0,#INBFB ;TO OUTPUT MOV @R0,#0 JMP INTR0 ;THIS ROUTINE FORMATS THE PLAY COMMAND ;(INTR). PLAY: SEL RB0 MOV R6,#0 ;SET PLAY SEL RB1 MOV R0,#INBFA MOV @R0,#10H ;SET UP BUFFERS MOV R0,#INBFB ;TO INPUT MOV @R0,#10H JMP INTR0 ;THIS ROUTINE FORMATS THE BEGIN ADDR COMMAND ;(INTR). BGAD: MOV R0,#BGADR BGAD0: JNI BGAD1 ;IF NEXT BYTE IN JMP BGAD0 BGAD1: MOVX A,@R0 ;GET COMMAND ANL A,#0F0H ;ROUND TO BOUNDARY MOV @R0,A BGAD2: JNI BGAD3 ;IF NEXT BYTE IN JMP BGAD2 BGAD3: MOVX A,@R0 INC R0 MOV @R0,A ;WRITE TO BUFFER JMP INTR0 ;THIS ROUTINE FORMATS THE END ADDR COMMAND ;(INTR). ENAD: MOV R0,#ENADR ENAD0: JNI ENAD1 ;IF NEXT BYTE IN JMP ENAD0 ENAD1: MOVX A,@R0 ;GET COMMAND ANL A,#0F0H ;ROUND TO BOUNDARY MOV @R0,A ENAD2: JNI ENAD3 ;IF NEXT BYTE IN JMP ENAD2 ENAD3: MOVX A,@R0 ;READ DATA INC R0 MOV @R0,A ;WRITE TO BUFFER JMP INTR0 ;THIS ROUTINE FORMATS THE SPEED COMMAND ;(INTR). SPED: MOV A,R2 ANL A,#3 ;GET SPEED ORL A,#50H ;SET COMMAND MOV R0,#SPEED MOV @R0,A JMP INTR0 ;THIS IS THE MAIN PROGRAM THAT CONTROLS ;ALL THE NON-REAL TIME EVENTS. ORG 100H MAIN: MOV R0,#3 MOV R2,#125 CLR A MAIN1: MOV @R0,A ;CLEAR ALL RAM INC R0 DJNZ R2,MAIN1 MOV R0,#ENADR+1 MOV @R0,#10H ;SET DUMMY END MOV R0,#SPEED MOV @R0,#53H ;SET HIGH SPEED CLR F0 CLR F1 MOVX A,@R0 ;CLEAR INTR EN I MOV A,#0BFH OUTL P2,A ;SET UP CNTRLS ORL P2,#40H ;ENA CNTR CALL REST ;DO RESET MAIN4: JNT0 MAIN4 ;IF NO OVERFLOW DIS I MOV A,R6 JZ MAINA ;IF PLAY IS SET MAIN5: JT0 MAIN5 ;GET TAILING EDGE ANL P2,#0BBH ;CLEAR COUNTER IN A,P1 MOV R4,A ;READ DATA LOW ORL P2,#44H ANL P2,#0F7H IN A,P1 ;READ DATA HIGH MOV R5,A ORL P2,#8 MOV R0,#BUFPTR MOV A,@R0 MOV R1,#INBFB+3 JB7 MAIN6 ;IF UPPER SET MOV R1,#INBFA+3 MAIN6: ANL A,#0FH ADD A,R1 MOV R1,A ;SET UP BUF PTR MOV A,R4 MOV @R1,A ;WRITE LOW TO BUFFER INC @R0 ;INCR PNTR INC R1 MOV A,R5 MOV @R1,A ;WRITE UPPER TO BUFFER INC @R0 MOV A,@R0 JB4 MAIN8 ;IF BUFFER FULL EN I JMP MAIN4 MAIN8: XRL A,#90H ;CLEAR D4,TOG D7 MOV @R0,A MOV A,R1 ANL A,#0E0H ;FORM BEGIN PTR CALL WRTO ;WRITE TO IBM EN I CALL ADST ;SET UP NEXT BUFFER JMP MAIN4 MAINA: MOV R0,#BUFPTR MOV R1,#INBFB+3 MOV A,@R0 JB7 MAINB ;IF UPPER SET MOV R1,#INBFA+3 MAINB: ANL A,#0FH ADD A,R1 MOV R1,A MOV A,@R1 ;READ BUFFER MOV R4,A ;SAVE DATA INC R1 INC @R0 MOV A,@R1 ;READ BUFFER MOV R5,A MAINC: JT0 MAINC ;WAIT FOR TRAILING EDGE MOV A,R4 OUTL P1,A ANL P2,#0BEH ;WRITE DATA LOW ORL P2,#41H ;CLEAR COUNTER MOV A,R5 OUTL P1,A ANL P2,#0FDH ORL P2,#2 ;WRITE DATA HIGH MOV A,#0FFH OUTL P1,A ;SET BUS TO INPUT INC @R0 MOV A,@R0 JB4 MAIND ;IF BUFFER EMPTY EN I JMP MAIN4 MAIND: XRL A,#90H ;CLEAR D4,TOG D7 MOV @R0,A MOV A,R1 ANL A,#0E0H MOV R2,A ;SAVE TEMP CALL ADST ;SET UP ADDRESS MOV A,R2 CALL REDI ;READ NEXT BLOCK EN I JMP MAIN4 ;THIS ROUITNE IS THE COMMAND SENDER TO THE ;VOICE BOARD. IT IS CALLED FROM INTR. CMSN: MOV R1,#COMBUF MOV R2,A ;SAVE DIGIT COUNT CMSN1: MOV A,@R1 ;GET DATA OUTL P1,A ;WRITE TO BOARD OUTL P1,A OUTL P1,A ANL P2,#0DFH ANL P2,#0DFH ANL P2,#0DFH ORL P2,#20H ;STROBE /WR ORL P2,#20H MOV A,#0FFH OUTL P1,A ;SET BUS TO READ MOV R3,#0 CMSN2: DJNZ R3,CMSN2 ;WAIT FOR BOARD INC R1 DJNZ R2,CMSN1 ;DO NEXT BYTE RET ;THIS ROUTINE WRITES OUT THE DATA FROM THE ;VOICE BOARD TO THE PC MEMORY. WRTO: MOV R0,A ;SET UP WHICH BUFFER MOV R2,#19 WRTO1: MOV A,@R0 ;READ DATA MOVX @R0,A ;WRITE TO PC WRTO2: JT1 WRTO2 ;WAIT FOR ACK INC R0 DJNZ R2,WRTO1 RET ;THIS ROUTINE READS THE DATA FROM THE ;PC AND STORES IT INTO A BUFFER. REDI: MOV R0,A MOV R2,#3 REDI0: MOV A,@R0 MOVX @R0,A ;WRITE COMMAND REDI1: JT1 REDI1 ;WAIT FOR ACK INC R0 DJNZ R2,REDI0 MOV R2,#16 REDI2: JNI REDI3 ;IF DATA IN JMP REDI2 REDI3: MOVX A,@R0 MOV @R0,A ;WRITE TO BUFFER INC R0 DJNZ R2,REDI2 RET ;THIS ROUTINE SETS UP THE ADDRESS HEADER IN ;THE SELECTED BUFFER. IT IS FROM MAIN. ORG 200H ADST: MOV R0,#BUFPTR MOV A,@R0 MOV R1,#INBFB+1 JB7 ADST1 ;IF UPPER SELECTED MOV R1,#INBFA+1 ADST1: MOV R0,#PCMPTR MOV A,@R0 ADD A,#10H MOV @R0,A MOV @R1,A ;WRITE BUFFER ADDR INC R0 INC R1 MOV A,@R0 ADDC A,#0 MOV @R0,A MOV @R1,A MOV A,R6 JZ ADST2 ;IF PLAY SET MOV R0,#PCMPTR MOV R1,#RECLST MOV A,@R0 MOV @R1,A INC R0 INC R1 MOV A,@R0 MOV @R1,A ;UPDATE LAST REC ADST2: RET ;THIS ROUTINE FORMATS THE 2 BYTE ADDRESS ;CODE INTO A 3 BYTE BIT CODE. IT IS CALLED ;FROM INTR. R0=SOURCE, R1=DEST. ADFR: MOV A,@R0 SWAP A ANL A,#0FH ;FORM MSD ORL A,#30H MOV @R1,A ;WRITE TO BUFFER INC R1 MOV A,@R0 SWAP A ANL A,#0F0H MOV R3,A INC R0 MOV A,@R0 SWAP A ANL A,#0FH ORL A,R3 MOV @R1,A ;WRITE TO BUFFER INC R1 MOV A,@R0 SWAP A ANL A,#0F0H MOV @R1,A RET ;THIS ROUTINE RESETS THE VOICE BOARD. IT IS ;CALLED FROM MAIN. REST: ANL P2,#0EFH MOV R3,#0 REST1: DJNZ R3,REST1 ;WAIT FOR RESET ORL P2,#10H REST2: DJNZ R3,REST2 RET END