$ROM(LARGE)
$DEBUG NOSYMBOLS NOPAGING

/*THIS PLM/51 PROGRAM CONTROLS THE DIGITAL
VOICE PROGRAMMER. IT IS TARGETED FOR AN 8751
RUNNING AT 10.00 MHZ.


VERSION 1.1		23 OCT 1986
BY			BILL HEIDEMAN


THESE ARE THE COMMANDS FOR THE CRT DISPLAY;
			DISPLAY
			-------
	DB		DBXXYYYY	BEGINNING
	DE		DEXXYYYY	END
	DR		DR			RECORD NEXT
	DP		DP			PRESENT PLAY
	DC		DC			CONTINUE PLAY
	DT		DT			TRIM VALUE
	DS		DS			VOICE SPEED
	DA		DA			ALL BOUNDARIES
	DZB		DZB			PROG BEGIN ADDR
	DZE		DZE			PROG END ADDR
	DZO		DZO			PROM OFFSET


			SET
			---
	SB		SBXXYYYY	BEGINING
	SE		SEXXYYYY	END
	SR		SRXX		RECORD NEXT
	SP		SPXX		PRESENT PLAY
	SC		SCXX		CONTINUE PLAY
	ST		STXX		TRIM VALUE
	SS		SSXX		SPEED VALUE
	SZB		SZBYYYY		PROG BEGIN ADDR
	SZE		SZEYYYY		PROG END ADDR
	SZO		SZOYYYY		PROM OFFSET		*/

VOICE_REC: DO;
$NOLIST
$INCLUDE(REG51.DCL)
$LIST
	DECLARE LIT LITERALLY 'LITERALLY';
	DECLARE DCL LIT 'DECLARE';
	DCL FOREVER LIT 'WHILE 1';
	DCL AUX LIT 'AUXILIARY';

	DCL MEM_PTR WORD MAIN;
	DCL MEMDATA BASED MEM_PTR BYTE AUX;
	DCL (VOCH,VOCM,VOCL,STATUS) BYTE MAIN;
	DCL (SWT_RD,SWT_VAL,SWT_LST) BYTE MAIN;
	DCL (ENTRY,J,DPL_SAVE,DPH_SAVE) BYTE MAIN;
	DCL (LOW_ADDR,MID_ADDR,HIGH_ADDR) BYTE;
	DCL (READ_PNTR,WRITE_PNTR) WORD;

	DCL (SWT_EDGE,LOOP,PLAY_INC,NO_CR) BIT;

	DCL MESS_START (50) WORD AT (0E000H) AUX;
	DCL MESS_STOP (50) WORD AT (0E200H) AUX;

	DCL ERR_ADDR WORD AT (0E1D8H) AUX;
	DCL	ERR_DATM BYTE AT (0E1DAH) AUX;
	DCL	ERR_DATD BYTE AT (0E1DBH) AUX;
	DCL PRG_BGN WORD AT (0E1DCH) AUX;
	DCL	PRG_END WORD AT (0E1DEH) AUX;
	DCL	PRG_OFF WORD AT (0E1E0H) AUX;
	DCL PLAY_CNT BYTE AT (0E3D8H) AUX;
	DCL REC_CNT BYTE AT (0E3D9H) AUX;
	DCL TRIM_CNT BYTE AT (0E3DAH) AUX;
	DCL SPEED BYTE AT (0E3DBH) AUX;
	DCL INT BYTE AT (0E3DCH) AUX;

	DCL DATABUS BYTE AT (8000H) AUX;
	DCL ADDRL BYTE AT (0A000H) AUX;
	DCL ADDRH BYTE AT (0C000H) AUX;
	DCL SWT_PORT BYTE AT (0A000H) AUX;

	DCL VOCCE LIT '0BCH';
	DCL VOCWR LIT '0B4H';
	DCL VOCRD LIT '0F8H';
	DCL VOCDIS LIT '0FEH';
	DCL BUSY LIT '80H';
	DCL EOS LIT '40H';
	DCL ERR LIT '20H';
	DCL OVR LIT '10H';
	DCL VOICE LIT '1';
	DCL PLAY LIT '2';
	DCL PROGM LIT '2';
	DCL REDUCE LIT '4';
	DCL VOC_SPD LIT '60H';
	DCL FIX_UP LIT '2';
 
	DCL CR LIT '0DH',LF LIT '0AH',EOF LIT '00H';
	DCL ESC LIT '1BH';

	DCL CAN_PNTR WORD;
	DCL CAN_OUT BASED CAN_PNTR BYTE CONSTANT;

	DCL OUT_BASE BYTE AT (0E1E0H) AUX;
	DCL OUT_PNTR WORD;
	DCL MES_OUT BASED OUT_PNTR BYTE AUX;

	DCL IN_BASE BYTE AT (0E3E0H) AUX;
	DCL IN_PNTR WORD;
	DCL MES_IN BASED IN_PNTR BYTE AUX;
  
	DCL SIGN_ON (*) BYTE CONSTANT (ESC,'G','VOICE',
' RECORDING DEVELOPMENT SYSTEM',CR,LF,LF,
	'COPYRIGHT 1986    MICRO-NETICS',CR,LF,
'VERSION 1.1',CR,LF,LF,LF,LF,EOF);
	DCL DONE_MSG (*) BYTE CONSTANT ('	DONE.',CR,LF,EOF);
	DCL ENTRY_ERROR (*) BYTE CONSTANT ('ENTRY ERROR',
							CR,LF,EOF);
	DCL PROMPT (*) BYTE CONSTANT (CR,LF,'*',EOF);
	DCL LINE_FEED (*) BYTE CONSTANT (LF,EOF);
	DCL DELETE_C (*) BYTE CONSTANT (8,' ',8,EOF);
	DCL TAB (*) BYTE CONSTANT ('        ',EOF);
	DCL ERR_AT (*) BYTE CONSTANT ('ERROR ADDRESS',EOF);
	DCL ERR_DAT (*) BYTE CONSTANT ('DEVICE DATA',EOF);
	DCL ERR_WAS (*) BYTE CONSTANT ('SHOULD BE',CR,LF,EOF);



/****************************************
*										*
*	THESE ARE THE EXTERNAL PROCEDURES.	*
*										*
****************************************/

	CAS: PROCEDURE EXTERNAL;
	END CAS;


	SET_UP: PROCEDURE EXTERNAL;
	END SET_UP;


/****************************************
*										*
*	THIS IS THE REAL TIME CLOCK.		*
*										*
****************************************/

	TIMER_ZERO: PROCEDURE INTERRUPT 1 USING 1;
		TH0=0BEH;	/* SET TO 20 MSEC */
		TL0=0E6H;

		SWT_RD=SWT_PORT;
		IF SWT_RD=SWT_LST THEN DO;
			IF ((SWT_LST XOR SWT_VAL) AND
				 (NOT(SWT_LST)) AND 18H) <>0
				 THEN SWT_EDGE=1;
		SWT_VAL=SWT_LST;
		END;

		ELSE SWT_LST=SWT_RD;

	END TIMER_ZERO;


/****************************************
*										*
*	THIS IS THE ROUTINE FOR INTR 1.		*
*	RECORDING STOP.						*
*										*
****************************************/

	REC_STOP: PROCEDURE INTERRUPT 2 USING 2;
		EX1=0;	/* DISABLE FURTHER INTS */
		DPL_SAVE=DPL;
		DPH_SAVE=DPH;
		MESS_STOP(REC_CNT)=DPH_SAVE;
		MESS_STOP(REC_CNT)=(256 *
				 MESS_STOP(REC_CNT)) + DPL_SAVE;
		LOOP=0;		/* CLEAR LOAD WAIT */
		EX0=0;		/* STOP CAS PULSES */

		SWT_VAL=SWT_VAL OR 8; /* SET STOP */
		SWT_EDGE=1;	
	END REC_STOP;


/************************************
*									*
*	THESE ROUTINES ARE FOR VOICE	*
*	BOARD COMMUNICATIONS.			*
*									*
************************************/

	BSY_CK: PROCEDURE;
		P1=VOCRD;
		P1=VOCRD;
		P1=VOCRD;
		DO WHILE (DATABUS AND BUSY)<>0;
			P1=0FCH;
			CALL TIME(1);
			P1=VOCRD;
			P1=VOCRD;
			P1=VOCRD;
		END;
		P1=0FCH;
		CALL TIME(1);
	END BSY_CK;


	WR_PULSE: PROCEDURE;
		P1=VOCCE;
		P1=VOCWR;
		P1=VOCWR;
		P1=VOCWR;
		P1=VOCCE;
		CALL TIME(1);
		CALL BSY_CK;
	END WR_PULSE;


	COM_SND: PROCEDURE(SELECT);
		DCL SELECT BYTE;
		DCL VALUES (4) BYTE CONSTANT(0,10H,20H,80H);

		DATABUS=VALUES(SELECT);
		CALL WR_PULSE;
	END COM_SND;


	ADDR_SND: PROCEDURE(SELECT,ADH,ADM,ADL);
		DCL (SELECT,ADH,ADM,ADL) BYTE;

		IF SELECT=4 THEN DATABUS=(ADH OR 30H);
		ELSE DATABUS=(ADH OR 40H);
		CALL WR_PULSE;
		DATABUS=ADM;
		CALL WR_PULSE;
		DATABUS=ADL;
		CALL WR_PULSE;
	END ADDR_SND;


	CNTRL_SND: PROCEDURE(RATE);
		DCL RATE BYTE;

		DATABUS=(RATE OR 50H);
		CALL WR_PULSE;
	END CNTRL_SND;


	LABL_SND: PROCEDURE;
	END LABL_SND;


	ADDR_RD: PROCEDURE;
		CALL BSY_CK;
		DATABUS=70H; /* SET UP ADD READ */
		P1=VOCCE;
		P1=VOCWR;
		P1=VOCWR;
		P1=VOCWR;
		P1=VOCCE;
		CALL TIME(1);

		P1=VOCRD;
		P1=VOCRD;
		P1=VOCRD;
		VOCH=DATABUS;
		P1=0FCH;
		CALL TIME(1);

		P1=VOCRD;
		P1=VOCRD;
		P1=VOCRD;
		VOCM=DATABUS;
		P1=0FCH;
		CALL TIME(1);

		P1=VOCRD;
		P1=VOCRD;
		P1=VOCRD;
		VOCL=DATABUS;
		CALL TIME(1);
		CALL BSY_CK;
		CALL TIME(1);
	END ADDR_RD;


	STAT_RD: PROCEDURE;
		P1=VOCRD;
		P1=VOCRD;
		P1=VOCRD;
		STATUS=DATABUS;
		P1=0FCH;
		CALL TIME(1);
	END STAT_RD;


	COMMAND: PROCEDURE(COM_NUM,AH,AM,AL,SPD);
		DCL (COM_NUM,AH,AM,AL,SPD) BYTE;

		IF COM_NUM<10 THEN DO CASE COM_NUM;
			CALL COM_SND(0);	/* NOP */
			CALL COM_SND(1);	/* START */
			CALL COM_SND(2);	/* STOP */
			CALL COM_SND(3);	/* REC */
			CALL ADDR_SND(4,AH,AM,AL);	/* START ADDR */
			CALL ADDR_SND(5,AH,AM,AL);	/*	STOP ADDR */
			CALL CNTRL_SND(SPD);	/* CNTROL */
			CALL LABL_SND;		/* LABEL */
			CALL ADDR_RD;		/* ADDR REQ */
			CALL STAT_RD;		/* STATUS REQ */
		END;
	END COMMAND;


/********************************
*								*
*	THESE ROUTINES ARE FOR		*
*	DATA CAPTURE.				*
*								*
********************************/


	EXP_ADDR: PROCEDURE(PNTR);
		DCL PNTR WORD;

		LOW_ADDR=LOW(SHL(PNTR,3));
		MID_ADDR=HIGH(SHL(PNTR,3));
		HIGH_ADDR=HIGH(SHR(PNTR,5));
	END EXP_ADDR;


	LOAD_WAIT: PROCEDURE(STRT);
		DCL STRT WORD;

		EA=0;
		LOOP=1;
		EX0=1;
		EX1=1;
		ET0=0;
		DPL=LOW(STRT);
		DPH=HIGH(STRT);
		CALL SET_UP;

		EA=1;
		DO WHILE LOOP<>0;	/* WAIT FOR INTR */
		END;

		ET0=1;
	END LOAD_WAIT;


	MEM_SHIFT: PROCEDURE(MESSG,CNT);
		DCL CNT WORD;
		DCL (I,MESSG) BYTE;

		DO I=MESSG TO REC_CNT;
			MESS_START(I)=MESS_START(I)-CNT;
			MESS_STOP(I)=MESS_STOP(I)-CNT;
		END;

		WRITE_PNTR=MESS_START(MESSG);
		READ_PNTR=MESS_START(MESSG)+CNT;

		DO WHILE READ_PNTR<MESS_START(REC_CNT);
			MEM_PTR=READ_PNTR;
			ENTRY=MEMDATA;	/* GET UPPER DATA */
			MEM_PTR=WRITE_PNTR;
			MEMDATA=ENTRY;	/* WRITE TO LOWER ADDR */
			WRITE_PNTR=WRITE_PNTR+1;
			READ_PNTR=READ_PNTR+1;
		END;
	END MEM_SHIFT;


/********************************
*								*
*	THESE ARE THE ROUTINES 		*
*	FOR CRT CONTROL.			*
*								*
********************************/

	SND_CAN: PROCEDURE(SEL);
		DCL SEL WORD;
		DCL N BYTE;

		CAN_PNTR=SEL;
		N=0FFH;
		DO WHILE N<>EOF;
			TI=0;
			N=CAN_OUT;
			IF N<>EOF THEN DO;
				SBUF=N;
				DO WHILE TI=0;
				END;
				CAN_PNTR=CAN_PNTR+1;
			END;
		END;
	END SND_CAN;


	SND_MSG: PROCEDURE;
		DCL N BYTE;

		OUT_PNTR=.OUT_BASE;
		N=0FFH;
		DO WHILE N<>EOF;
			TI=0;
			N=MES_OUT;
			IF N<>EOF THEN DO;
				SBUF=N;
				DO WHILE TI=0;
				END;
				OUT_PNTR=OUT_PNTR+1;
			END;
		END;

		IF NO_CR=0 THEN DO;
			TI=0;
			SBUF=CR;
			DO WHILE TI=0;
			END;
			TI=0;
			SBUF=LF;
			DO WHILE T1=0;
			END;
		END;

	END SND_MSG;


	IN_MSG: PROCEDURE;
		DCL N BYTE;

		N=0;
		IN_PNTR=.IN_BASE;
		DO WHILE N<>CR;
			DO WHILE RI=0;
			END;
			RI=0;
			N=SBUF AND 7FH;
			IF N=7FH THEN DO;
				IN_PNTR=IN_PNTR-1;
				CALL SND_CAN(.DELETE_C);
			END;

			ELSE DO;
				MES_IN=N;
				IN_PNTR=IN_PNTR+1;

				TI=0;
				SBUF=N;
				DO WHILE TI=0;
				END;
			END;
		END;
	END IN_MSG;


	BIN_CONV: PROCEDURE(STRT,LEN) WORD;
		DCL (STRT,LEN,I,VAL) BYTE;
		DCL BIN_RET WORD;

		IN_PNTR=((.IN_BASE)+(STRT+LEN-1));
		BIN_RET=0;
		VAL=0;

		DO I=0 TO LEN;
			IF MES_IN>40H THEN
				BIN_RET=BIN_RET OR SHL((
					DOUBLE(MES_IN-37H)),VAL);
			ELSE BIN_RET=BIN_RET OR SHL((
					DOUBLE(MES_IN-30H)),VAL);
			VAL=VAL+4;
			IN_PNTR=IN_PNTR-1;
		END;
		RETURN BIN_RET;
	END BIN_CONV;


	DIS_ASCII: PROCEDURE(AD_PNTR,LEN);
		DCL (LEN,I) BYTE;
		DCL AD_PNTR WORD;
		DCL VAL BASED AD_PNTR BYTE AUX;

		OUT_PNTR=.OUT_BASE;
		DO I=0 TO LEN-1;
			IF (VAL AND 0F0H)<0A0H THEN
				MES_OUT=SHR((VAL AND 0F0H),4)
						+ 30H;
			ELSE MES_OUT=SHR((VAL AND 0F0H),4)
						+ 37H;
			OUT_PNTR=OUT_PNTR+1;
			IF (VAL AND 0FH)<10 THEN
				MES_OUT=(VAL AND 0FH) + 30H;
			ELSE MES_OUT=(VAL AND 0FH) + 37H;
			OUT_PNTR=OUT_PNTR+1;
			AD_PNTR=AD_PNTR+1;
		END;
		MES_OUT=EOF;
	END DIS_ASCII;


	COM_SET: PROCEDURE;
		IN_PNTR=.IN_BASE+1;
		IF MES_IN='B' THEN
			MESS_START(LOW(BIN_CONV(
				2,2)))=(BIN_CONV(4,4));

		ELSE IF MES_IN='E' THEN
			MESS_STOP(LOW(BIN_CONV(
				2,2)))=(BIN_CONV(4,4));

		ELSE IF MES_IN='R' THEN
			REC_CNT=LOW(BIN_CONV(2,2));

		ELSE IF MES_IN='P' THEN
			PLAY_CNT=LOW(BIN_CONV(2,2));

		ELSE IF MES_IN='T' THEN
			TRIM_CNT=LOW(BIN_CONV(2,2));

		ELSE IF MES_IN='S' THEN DO;
			SPEED=LOW(BIN_CONV(2,2));
			CALL COMMAND(6,0,0,0,SPEED);
		END;

		ELSE IF MES_IN='C' THEN DO;
			IF LOW(BIN_CONV(2,2))<>0 THEN 
				PLAY_INC=1;
			ELSE PLAY_INC=0;
		END;

		ELSE IF MES_IN='Z' THEN DO;
			IN_PNTR=.IN_BASE+2;
			IF MES_IN='B' THEN
				PRG_BGN=BIN_CONV(3,4);
			ELSE IF MES_IN='E' THEN
				PRG_END=BIN_CONV(3,4);
			ELSE IF MES_IN='O' THEN
				PRG_OFF=BIN_CONV(3,4);
			ELSE DO;
				CALL SND_CAN(.ENTRY_ERROR);
			END;
		END;

		ELSE CALL SND_CAN(.ENTRY_ERROR);
	END COM_SET;


	COM_DISP: PROCEDURE;
		IN_PNTR=.IN_BASE+1;
		IF MES_IN='B' THEN DO;
			CALL DIS_ASCII(.MESS_START
				(LOW(BIN_CONV(2,2))),2);
			OUT_PNTR=.OUT_BASE;
			CALL SND_MSG;
		END;

		ELSE IF MES_IN='E' THEN DO;
			CALL DIS_ASCII(.MESS_STOP
				(LOW(BIN_CONV(2,2))),2);
			OUT_PNTR=.OUT_BASE;
			CALL SND_MSG;
		END;

		ELSE IF MES_IN='R' THEN DO;
			CALL DIS_ASCII(.REC_CNT,1);
			OUT_PNTR=.OUT_BASE;
			CALL SND_MSG;
		END;

		ELSE IF MES_IN='P' THEN DO;
			CALL DIS_ASCII(.PLAY_CNT,1);
			OUT_PNTR=.OUT_BASE;
			CALL SND_MSG;
		END;

		ELSE IF MES_IN='T' THEN DO;
			CALL DIS_ASCII(.TRIM_CNT,1);
			OUT_PNTR=.OUT_BASE;
			CALL SND_MSG;
		END;

		ELSE IF MES_IN='S' THEN DO;
			CALL DIS_ASCII(.SPEED,1);
			OUT_PNTR=.OUT_BASE;
			CALL SND_MSG;
		END;

		ELSE IF MES_IN='C' THEN DO;
			OUT_PNTR=.OUT_BASE;
			IF PLAY_INC<>0 THEN
				MES_OUT=31H;
			ELSE MES_OUT=30H;
			OUT_PNTR=OUT_PNTR+1;
			MES_OUT=EOF;
			OUT_PNTR=.OUT_BASE;
			CALL SND_MSG;
		END;

		ELSE IF MES_IN='A' THEN DO;
			DO INT=0 TO REC_CNT;
				CALL DIS_ASCII(.INT,1);
				NO_CR=1;
				CALL SND_MSG;
				CALL SND_CAN(.TAB);
				CALL DIS_ASCII(.MESS_START
					(INT),2);
				CALL SND_MSG;
				CALL SND_CAN(.TAB);
				
				CALL EXP_ADDR(MESS_START(INT));
				CALL DIS_ASCII(.HIGH_ADDR,1);
				CALL DIS_ASCII(.MID_ADDR,1);
				CALL DIS_ASCII(.LOW_ADDR,1);
				CALL SND_MSG;
				CALL SND_CAN(.TAB);

				CALL DIS_ASCII(.MESS_STOP
					(INT),2);
				CALL SND_MSG;
				CALL SND_CAN(.TAB);

				NO_CR=0;
				CALL EXP_ADDR(MESS_STOP(INT));
				CALL DIS_ASCII(.HIGH_ADDR,1);
				CALL DIS_ASCII(.MID_ADDR,1);
				CALL DIS_ASCII(.LOW_ADDR,1);
				CALL SND_MSG;

				TI=0;
				SBUF=LF;
				DO WHILE TI=0;
				END;
			END;
		END;

		ELSE IF MES_IN='Z' THEN DO;
			IN_PNTR=.IN_BASE+2;
			IF MES_IN='B' THEN DO;
				CALL DIS_ASCII(.PRG_BGN,2);
				CALL SND_MSG;
			END;
			ELSE IF MES_IN='E' THEN DO;
				CALL DIS_ASCII(.PRG_END,2);
				CALL SND_MSG;
			END;
			ELSE IF MES_IN='O' THEN DO;
				CALL DIS_ASCII(.PRG_OFF,2);
				CALL SND_MSG;
			END;
			ELSE CALL SND_CAN(.ENTRY_ERROR);
		END;

		ELSE CALL SND_CAN(.ENTRY_ERROR);
	END COM_DISP;



/****************************************
*										*
*	THESES ROUTINES ARE FOR PROM		* 
*	PROGRAMMING.						*
*										*
****************************************/

	DIS_ERROR: PROCEDURE;
		CALL SND_CAN(.TAB);
		CALL SND_CAN(.ERR_AT);
		CALL SND_CAN(.TAB);
		CALL SND_CAN(.ERR_DAT);
		CALL SND_CAN(.TAB);
		CALL SND_CAN(.ERR_WAS);

		NO_CR=1;
		CALL SND_CAN(.TAB);
		CALL SND_CAN(.TAB);
		CALL DIS_ASCII(.ERR_ADDR,2);

		CALL SND_CAN(.TAB);
		CALL SND_CAN(.TAB);
		CALL DIS_ASCII(.ERR_DATM,1);

		NO_CR=0;
		CALL SND_CAN(.TAB);
		CALL SND_CAN(.TAB);
		CALL DIS_ASCII(.ERR_DATD,1);
		CALL SND_MSG;
	END DIS_ERROR;


	TRANS: PROCEDURE;
		DCL CNTR WORD;

		P1=7EH;
		CALL TIME(100);

		DO CNTR=0 TO (PRG_END-PRG_BGN);
			MEM_PTR=(PRG_BGN+CNTR);
			ADDRL=LOW(PRG_OFF+CNTR);
			ADDRH=HIGH(PRG_OFF+CNTR);
			MEMDATA=DATABUS;
		END;

		CALL SND_CAN(.DONE_MSG);
	END TRANS;

	PROG: PROCEDURE;
		DCL CNTR WORD;
		DCL (X,COMP,REP) BYTE;

		EA=0;	 /* DISABLE ALL INTRS */
		P1=0CEH; /* TURN ON HV */
		CALL TIME(100);

		DO CNTR=0 TO (PRG_END-PRG_BGN);
			X=0; /* SET UP ADDR/DATA */
			MEM_PTR=(PRG_BGN+CNTR);
			ADDRL=LOW(PRG_OFF+CNTR);
			ADDRH=(HIGH(PRG_OFF+CNTR) OR 80H);
			DATABUS=MEMDATA;
			P1=8EH;
			COMP=0FFH;

			DO WHILE (X<>25) AND (COMP<>0);
				P1=0EH;
				CALL	TIME(9); /* PULSE CE */
				P1=8EH;

				X=X+1;
				P1=0CEH; /* DO COMPARE */
				ADDRH=HIGH(PRG_OFF+CNTR);
				IF DATABUS=MEMDATA THEN
					COMP=0;
			END;

			IF COMP=0 THEN DO REP=0 TO (3*X);
				P1=0EH;
				CALL TIME(9);
			END;

			ELSE DO;
				ERR_ADDR=(PRG_BGN+CNTR);
				ERR_DATM=MEMDATA;
				ERR_DATD=DATABUS;
				CALL DIS_ERROR;
				CNTR=(PRG_END-PRG_BGN);
			END;

			P1=0CEH;
		END;

		P1=0FEH;
		ADDRH=80H;
		EA=1;	/* ENABLE INTRS */
		CALL SND_CAN(.DONE_MSG);
	END PROG;


	VERIF: PROCEDURE;
		DCL CNTR WORD;

		P1=7EH;
		CALL TIME(100);

		DO CNTR=0 TO (PRG_END-PRG_BGN);
			MEM_PTR=(PRG_BGN+CNTR);
			ADDRL=LOW(PRG_OFF+CNTR);
			ADDRH=HIGH(PRG_OFF+CNTR);
			IF MEMDATA<>DATABUS THEN DO;
				ERR_ADDR=(PRG_BGN+CNTR);
				ERR_DATM=MEMDATA;
				ERR_DATD=DATABUS;
				CALL DIS_ERROR;
				CNTR=(PRG_END-PRG_BGN);
			END;
		END;

		CALL SND_CAN(.DONE_MSG);
	END VERIF;


/********************************
*								*
*	THESE ROTUINES ARE HIGH		*
*	LEVEL COMMANDS TO THE		*
*	VOICE BOARD.				*
*								*
********************************/

	PLAY_MSG: PROCEDURE;
		CALL COMMAND(0,0,0,0,0); /* SET PLAY */
		CALL EXP_ADDR(MESS_START(PLAY_CNT));
		CALL COMMAND(4,HIGH_ADDR,MID_ADDR,
						LOW_ADDR,0);
		CALL EXP_ADDR(MESS_STOP(PLAY_CNT));
		CALL COMMAND(5,HIGH_ADDR,MID_ADDR,
						LOW_ADDR,0);
		CALL COMMAND(1,0,0,0,0); /* SET START */
	END PLAY_MSG;



/********************************
*								*
*	THIS IS THE MAIN LOOP		*	
*								*
********************************/
	
	INIT: DO;
		P1=0FFH;
		ADDRL=00;
		ADDRH=80H;
		DATABUS=00;
		SWT_EDGE=0;
		PX0=1;		/* EXTERN INTR */
		IT0=1;
		PX1=1;
	
		SCON=50H;	/* USART	*/

		TH1=0F5H;	/*	TIMER	*/
		TL1=0F5H;	/*	2400 B	*/
		TMOD=21H;
		EA=1;
		TR0=1;
		TR1=1;
		ET0=1;

		CALL COMMAND(0,0,0,0,0);	/* RESET ERR	*/
		SPEED=(SHR(SWT_VAL,5) AND 3);
		CALL COMMAND(6,0,0,0,SPEED); /* SEND SPEED	*/
		CALL COMMAND(4,0,0,0,0);	/*	SEND START ADDR	*/

		MESS_START(0)=0;
		PLAY_CNT=0;
		REC_CNT=0;
		TRIM_CNT=20H;
		NO_CR=0;
		PLAY_INC=0;
		PRG_BGN=0;
		PRG_END=7FFFH;
		PRG_OFF=0;

		CALL SND_CAN(.SIGN_ON);	/* SEND SIGN ON */
		CALL SND_CAN(.PROMPT);

	END INIT;


	MAIN_LOOP: DO FOREVER;
		IF RI<>0 THEN DO;
			CALL IN_MSG;
			CALL SND_CAN(.LINE_FEED);
			IN_PNTR=.IN_BASE;

			IF MES_IN='S' THEN
				CALL COM_SET;
			ELSE IF MES_IN='D' THEN
				CALL COM_DISP;

			CALL SND_CAN(.PROMPT);

		END;

		IF SWT_EDGE<>0 THEN DO;
			SWT_EDGE=0;
			IF (SWT_VAL AND VOICE)<>0 THEN DO;
				IF (SWT_VAL AND REDUCE)<>0 THEN DO;
					IF (SWT_VAL AND FIX_UP)<>0 THEN DO;
						CALL MEM_SHIFT(0,MESS_START(0));
						DO J=1 TO (REC_CNT-1);
							CALL MEM_SHIFT(J,(MESS_START(J)-
									MESS_STOP(J-1)));
						END;
						CALL PLAY_MSG;
					END;
					ELSE IF (SWT_VAL AND 8)<>0 THEN DO;
						MESS_STOP(PLAY_CNT)=
							MESS_STOP(PLAY_CNT)-TRIM_CNT;
						CALL PLAY_MSG;
					END;
					ELSE DO;
						MESS_START(PLAY_CNT)=
							MESS_START(PLAY_CNT)+TRIM_CNT;
						CALL PLAY_MSG;
					END;
				END;

				ELSE IF (SWT_VAL AND 8)<>0 THEN DO; 
					CALL COMMAND(2,0,0,0,0); /* SET STOP */
				END;

				ELSE DO;
					IF (SWT_VAL AND PLAY)<>0 THEN DO;
						IF REC_CNT<>0 THEN DO;
							CALL PLAY_MSG;
							IF PLAY_INC<>0 THEN DO;
								IF PLAY_CNT=REC_CNT-1 THEN
										PLAY_CNT=0;
								ELSE PLAY_CNT=PLAY_CNT+1;
							END;
						END;
					END;

					ELSE DO;
						CALL COMMAND(3,0,0,0,0); /*	 SET RECORD */
						CALL EXP_ADDR(MESS_START(REC_CNT));
						CALL COMMAND(4,HIGH_ADDR,MID_ADDR,
									LOW_ADDR,0);
						CALL COMMAND(1,0,0,0,0); /* SET START  */
						CALL LOAD_WAIT(MESS_START(REC_CNT));
						REC_CNT=REC_CNT+1;
						MESS_START(REC_CNT)=MESS_STOP(REC_CNT-1);
					END;
				END;
			END;

			ELSE DO;	/* PROGRAM MODE */
				IF (SWT_VAL AND 8)<>0 THEN DO;
					CALL VERIF;	/* DO VERIFY */
				END;
				ELSE DO;
					IF (SWT_VAL AND PROGM)<>0 THEN DO;
						CALL PROG;	/* DO PROGRAM */
						CALL VERIF;	/* DO VERIFY */
					END;

					ELSE DO;
						CALL TRANS;	/* DO TRANSFER */
					END;
				END;
			END;

		END;

	END MAIN_LOOP;
END VOICE_REC;
