; LarkSlave.dsm
; Code for Lark Slave processor
; L. Stewart November 3, 1982  3:55 PM
; L. Stewart December 27, 1982  1:23 PM, fix silence detect bug
; L. Stewart December 27, 1982  5:02 PM, delay loops
; L. Stewart March 10, 1983  7:52 PM, mode for back door
; L. Stewart March 14, 1983  9:48 AM
;	TEST replaced by OR (faster)
;	loop unrolling reorganized to permit read after write
;	mode bit 2 added for O2I2

; There is a region of the Slave ROM which contains interleaved
; 256 byte tables (or a single 256 word table).  This table, whose
; base is at OutGain, converts a u255 coded byte to a 16 bit
; two's complement value.  There are a number of these tables,
; the main CPU tells the Slave which one to use by changing
; the pointer stored in OutGain

; There is a region of the slave ROM which translates from the two's
; complement value system back to u255.  The table is 2048 bytes
; long and converts from positive values only.  Negative values are
; handled by converting to positive.  The output shift register is
; assigned two addresses, one of them, OSRNegPort, has the side
; effect of setting the U255 sign bit.

; There are a number of 256 byte tables in the ROM.  Those
; at SilenceLoc and SilenceLoc+1 are the low and high bytes,
; respectively, of the silence detection value for the given
; shift register contents. These two tables are interleaved
; ( a word table ). The other tables, found at locations passed
; in InGain, contain the shift register value attenuated by
; 0 dB, 5 dB, 10 dB etc. These latter tables are maps from
; U255 spoace to U255 space.

; There is an EQU only for the high byte of SilenceLoc,
; since the silence detection code takes advantage of there
; being no dependence on the sign of the sample.

; organization of the slave EPROM
; E000 : xxxx code
; EA00 : EBFF U255 -> linear -0 dB (256 words)
; EC00 : EDFF U255 -> linear -3 dB (256 words)
; EE00 : EFFF U255 -> linear -6 dB (256 words)
; F000 : F7FF linear -> U255 table (2048 bytes)
; F800 : F9FF U255 -> silence value  (256 words)
; FA00 : FAFF U255 -> U255 -0dB (256 bytes)
; FB00 : FBFF U255 -> U255 -5dB (256 bytes)
; FC00 : FCFF U255 -> U255 -10dB (256 bytes)
; FD00 : FDFF U255 -> U255 -15dB (256 bytes)
; FE00 : FEFF U255 -> U255 -20dB (256 bytes)
; FFF0 : FFF5 long jump to 0:E000

; Constants

; Ports
ISRPort	EQU	000H
OSRPosPort EQU	004H
OSRNegPort EQU	00CH

; addresses in main memory
InBuf1	EQU	0D400H
OutBuf1	EQU	0D580H
OutBuf2	EQU	0D700H
OutBuf3	EQU	0D880H
InBuf2	EQU	0D880H

BltCount	EQU	0D9E8H
BltFrom	EQU	0D9EAH
BltTo	EQU	0D9ECH
ModeFlag	EQU	0D9EEH
In2Gain	EQU	0D9F0H
In1Gain	EQU	0D9F2H
OutGain	EQU	0D9F4H
BufPtr	EQU	0D9F6H
Sil1Val	EQU	0D9F8H
Sil2Val	EQU	0D9FAH
CodeLoc	EQU	0D9FCH
CodeLen	EQU	0D9FEH

; constants
LastIL	EQU	320
HalfIL	EQU	160
O3Delay	EQU	8
O2Delay	EQU	15
Prog03I1	EQU	1
Prog02I2	EQU	2
ProgBLT	EQU	4
ProgJMP	EQU	5

; addresses in local memory
RAMAdr	EQU	02000H
MaxCode	EQU	00300H		; Ram code in words
SPIN	EQU	027F0H		; initial stack pointer, top of the RAM
MuTbl	EQU	0F000H		; linear to U255, 2048 bytes
MaxMuVal EQU	07FH
NegMaxMuVal EQU	0FFH
SilLocHi EQU	0F8H		; U255 to silence value, 512 bytes

SPACE	SEGMENT
C←GROUP GROUP SPACE, C←CODE, C←DATA
SPACE	ENDS

C←CODE	SEGMENT

; .ld file will set up the data segment at 02600H

C←DATA	SEGMENT

; Save area for OutBuf1 for use by both loops
; This table is rotated by 3 because the block of 8 samples is read
; from the shared memory during Loop 3
SOut1	LABEL	BYTE
SO1L3	DB	?
SO1L4	DB	?
SO1L5	DB	?
SO1L6	DB	?
SO1L7	DB	?
SO1L0	DB	?
SO1L1	DB	?
SO1L2	DB	?

; Save area for OutBuf2 for use by both loops
; This table is rotated by 4 because the block of 8 samples is read
; from the shared memory during Loop 4
SOut2	LABEL	BYTE
SO2L4	DB	?
SO2L5	DB	?
SO2L6	DB	?
SO2L7	DB	?
SO2L0	DB	?
SO2L1	DB	?
SO2L2	DB	?
SO2L3	DB	?

; Save area for OutBuf3 for use by O3I1 loop
; This table is rotated by 5 because the block of 8 samples is read
; from the shared memory during Loop 5
SOut3	LABEL	BYTE
SO3L5	DB	?
SO3L6	DB	?
SO3L7	DB	?
SO3L0	DB	?
SO3L1	DB	?
SO3L2	DB	?
SO3L3	DB	?
SO3L4	DB	?

; Save area for InBuf2 for use by O2I2 loop
; This table is rotated by 2 because the block of 8 samples is read
; from the shared memory during Loop 2
SIn2	LABEL	BYTE
SI2L2	DB	?
SI2L3	DB	?
SI2L4	DB	?
SI2L5	DB	?
SI2L6	DB	?
SI2L7	DB	?
SI2L0	DB	?
SI2L1	DB	?


; Save area for InBuf1 for use by both loops
; This table is rotated by 1 because the block of 8 samples is written
; from the shared memory during Loop 1
SIn1	LABEL	BYTE
SI1L1	DB	?
SI1L2	DB	?
SI1L3	DB	?
SI1L4	DB	?
SI1L5	DB	?
SI1L6	DB	?
SI1L7	DB	?
SI1L0	DB	?

; O3I1 loop variables
; Save area for input and output gain addresses
ModeLow	LABEL	BYTE
ModeBits	DW	?
SIGain	DW	?
SOGain	DW	?

; O2I2 loop variables
; Save area for gains
; Save area for input and output gain addresses
SI2Gain	DW	?
SI1Gain	DW	?
SilVal1	DW	?
SilVal2	DW	?

C←DATA	ENDS

ASSUME	CS:C←CODE,DS:C←DATA,SS:C←DATA,ES:C←DATA

; This code is at loc E000 (or 0)
	JMP	HaltSlave
	DB	0
	DW	0
	DW	0
	DW	0E00CH	; NMI IP
	DW	0	; NMI CS

; this code at address E00C
SlaveNMI:
; set up segment registers
	MOV	AX,0
	MOV	DS,AX
	MOV	ES,AX
	MOV	SS,AX
; initialize registers for loop
	MOV	SP,SPIN		; probably don't need a stack but...
	CLD
	XOR	BX,BX
	MOV	SI,[BX+CodeLoc]
	CMP	SI,Prog03I1
	JNZ	TestO2I2
	JMP	LoopO3I1
TestO2I2:
	CMP	SI,Prog02I2
	JNZ	TestBLT
	JMP	LoopO2I2
TestBLT:
	CMP	SI,ProgBLT
	JNZ	TestJMP
	JMP	LoopBLT
TestJMP:
	CMP	SI,ProgJMP
	JNZ	LoadCode
	JMP	LoopJMP
LoadCode:
	XOR	BX,BX
	MOV	CX,[BX+CodeLen]
	CMP	CX,MaxCode
	JBE	LenOK
	MOV	CX,MaxCode
LenOk:
	MOV	DI,RAMAdr	; address of RAM
	REP MOVSW
	MOV	BX,RAMAdr
	JMP	BX

; useful routine
HaltSlave:
	HLT
	JMP	HaltSlave
; does a blt from place to place
LoopBLT:
	XOR	BX,BX
	MOV	SI,[BX+BltFrom]
	MOV	DI,[BX+BltTo]
	MOV	CX,[BX+BltCount]
	CLD
	REP	MOVSW
	JMP	HaltSlave

; does a jump
LoopJMP:
	XOR	BX,BX
	MOV	BX,[BX+BltFrom]
	JMP	BX

; Loop Out 3 In 1
; There are 8 copies of the basic code ( 8 x loop unrolled) because different
; things happen at the beginning of each loop

; Loop 0
; 	read InGain, OutGain
; 	write sample pointer
; 	maybe write silence value  (end of packet only)
; Loop 1 	Write InBuf1
; Loop 2 	Read OutBuf3
; Loop 3 	Read OutBuf1
; Loop 4 	Read OutBuf2
; Loop 5 	write zeros in OutBuf1
;		CLD
; Loop 6 	write zeros in OutBuf2
; Loop 7 	write zeros in OutBuf3

LoopO3I1:
; set up segment registers
	MOV	AX,0
	MOV	DS,AX
	MOV	ES,AX
	MOV	SS,AX
; initialize registers for loop
	MOV	SP,SPIN		; probably don't need a stack but...
	XOR	DX,DX		; initialize silence register
	XOR	BP,BP		; initialize buffer pointer
	CLD			; string ops increment
	JMP	MidPktO3I1
; read InGain and OutGain
; write BufBtr
; write SilVal on wraparound

MidPktO3I1:
	MOV	SI,In1Gain
	MOV	DI,OFFSET SIGain
	WAIT
	MOVSW			; read In1Gain
	MOVSW			; read OutGain
	MOV	[SI],BP		; store pointer (was in BP)
	MOV	AX,[-8+SI]
	MOV	ModeBits,AX
	JMP	StartL0

EndPktO3I1:
	MOV	SI,In1Gain
	MOV	DI,OFFSET SIGain
	WAIT
	MOVSW			; read In1Gain
	MOVSW			; read OutGain
	MOV	[SI],BP		; store pointer (was in BP)
	MOV	[2+SI],DX	; store Sil1Val
	XOR	DX,DX

StartL0:
; Loop 0, label is xxxL0
	IN	AL,ISRPort	; must be after end of TS1
	MOV	BL,AL
	SHL	BX,1
	MOV	BH,SilLocHi
	ADD	DX,[BX]		; add to silence reg.
	MOV	BX,SIGain
	XLATB			; get sample, with gain
	MOV	SI1L0,AL	; sample to input save area

	MOV	CX,O3Delay
O3DL0:
	LOOP	O3DL0

	MOV	DI,SOGain
	MOV	BL,SO1L0
	XOR	BH,BH
	SHL	BX,1
	MOV	AX,[DI][BX]	; first MOV, others ADD
	MOV	BL,SO2L0
	XOR	BH,BH
	SHL	BX,1
	ADD	AX,[DI][BX]
; added for mode stuff
	TEST	ModeLow,1
	JZ	O3ML0
	MOV	BL,SI1L0
	XOR	BH,BH
	SHL	BX,1
	ADD	AX,[DI][BX]
O3ML0:
	MOV	BL,SO3L0
	XOR	BH,BH
	SHL	BX,1
	ADD	AX,[DI][BX]
	JNS	PosL0
	NEG	AX
	TEST	AX,0F800H	; Check for underflow
	JNZ	UFlowL0
	MOV	BX,AX
	MOV	AL,[MuTbl+BX]
	OR	AL,080H
	OUT	OSRNegPort,AL
	JMP	EndL0

UFlowL0:
	MOV	AL,NegMaxMuVal	; smallest mu-law
	OUT	OSRNegPort,AL
	JMP	EndL0

PosL0:
	TEST	AX,0F800H	; Check for underflow
	JNZ	OFlowL0
	MOV	BX,AX
	MOV	AL,[MuTbl+BX]
	OUT	OSRPosPort,AL
	JMP	EndL0

OFlowL0:
	MOV	AL,MaxMuVal	; largest mu-law
	OUT	OSRPosPort,AL

EndL0:

; LOOP 1

; write 4 words to inbuf 1
	MOV	SI,OFFSET SIn1
	MOV	DI,InBuf1
	ADD	DI,BP
	MOV	CX,4
	WAIT
	REP MOVSW

; Loop 1, label is xxxL1
	IN	AL,ISRPort
	MOV	BL,AL
	SHL	BX,1
	MOV	BH,SilLocHi
	ADD	DX,[BX]		; add to silence reg.
	MOV	BX,SIGain
	XLATB			; get sample, with gain
	MOV	SI1L1,AL	; sample to input save area

	MOV	CX,O3Delay
O3DL1:
	LOOP	O3DL1

	MOV	DI,SOGain
	MOV	BL,SO1L1
	XOR	BH,BH
	SHL	BX,1
	MOV	AX,[DI][BX]	; first MOV, others ADD
	MOV	BL,SO2L1
	XOR	BH,BH
	SHL	BX,1
	ADD	AX,[DI][BX]
; added for mode stuff
	TEST	ModeLow,1
	JZ	O3ML1
	MOV	BL,SI1L1
	XOR	BH,BH
	SHL	BX,1
	ADD	AX,[DI][BX]
O3ML1:
	MOV	BL,SO3L1
	XOR	BH,BH
	SHL	BX,1
	ADD	AX,[DI][BX]
	JNS	PosL1
	NEG	AX
	TEST	AX,0F800H	; Check for underflow
	JNZ	UFlowL1
	MOV	BX,AX
	MOV	AL,[MuTbl+BX]
	OR	AL,080H
	OUT	OSRNegPort,AL
	JMP	EndL1

UFlowL1:
	MOV	AL,NegMaxMuVal	; smallest mu-law
	OUT	OSRNegPort,AL
	JMP	EndL1

PosL1:
	TEST	AX,0F800H	; Check for underflow
	JNZ	OFlowL1
	MOV	BX,AX
	MOV	AL,[MuTbl+BX]
	OUT	OSRPosPort,AL
	JMP	EndL1

OFlowL1:
	MOV	AL,MaxMuVal	; largest mu-law
	OUT	OSRPosPort,AL

EndL1:

; LOOP 2

; read 4 words from outbuf 3
	MOV	SI,OutBuf3
	ADD	SI,BP
	MOV	DI,OFFSET SOut3
	MOV	CX,4
	WAIT
	REP MOVSW

; Loop 2, label is xxxL2
	IN	AL,ISRPort
	MOV	BL,AL
	SHL	BX,1
	MOV	BH,SilLocHi
	ADD	DX,[BX]		; add to silence reg.
	MOV	BX,SIGain
	XLATB			; get sample, with gain
	MOV	SI1L2,AL	; sample to input save area

	MOV	CX,O3Delay
O3DL2:
	LOOP	O3DL2

	MOV	DI,SOGain
	MOV	BL,SO1L2
	XOR	BH,BH
	SHL	BX,1
	MOV	AX,[DI][BX]	; first MOV, others ADD
	MOV	BL,SO2L2
	XOR	BH,BH
	SHL	BX,1
	ADD	AX,[DI][BX]
; added for mode stuff
	TEST	ModeLow,1
	JZ	O3ML2
	MOV	BL,SI1L2
	XOR	BH,BH
	SHL	BX,1
	ADD	AX,[DI][BX]
O3ML2:
	MOV	BL,SO3L2
	XOR	BH,BH
	SHL	BX,1
	ADD	AX,[DI][BX]
	JNS	PosL2
	NEG	AX
	TEST	AX,0F800H	; Check for underflow
	JNZ	UFlowL2
	MOV	BX,AX
	MOV	AL,[MuTbl+BX]
	OR	AL,080H
	OUT	OSRNegPort,AL
	JMP	EndL2

UFlowL2:
	MOV	AL,NegMaxMuVal	; smallest mu-law
	OUT	OSRNegPort,AL
	JMP	EndL2

PosL2:
	TEST	AX,0F800H	; Check for underflow
	JNZ	OFlowL2
	MOV	BX,AX
	MOV	AL,[MuTbl+BX]
	OUT	OSRPosPort,AL
	JMP	EndL2

OFlowL2:
	MOV	AL,MaxMuVal	; largest mu-law
	OUT	OSRPosPort,AL

EndL2:

; LOOP 3

; read 4 words from outbuf 1
	MOV	SI,OutBuf1
	ADD	SI,BP
	MOV	DI,OFFSET SOut1
	MOV	CX,4
	WAIT
	REP MOVSW

; Loop 3, label is xxxL3
	IN	AL,ISRPort
	MOV	BL,AL
	SHL	BX,1
	MOV	BH,SilLocHi
	ADD	DX,[BX]		; add to silence reg.
	MOV	BX,SIGain
	XLATB			; get sample, with gain
	MOV	SI1L3,AL	; sample to input save area

	MOV	CX,O3Delay
O3DL3:
	LOOP	O3DL3

	MOV	DI,SOGain
	MOV	BL,SO1L3
	XOR	BH,BH
	SHL	BX,1
	MOV	AX,[DI][BX]	; first MOV, others ADD
	MOV	BL,SO2L3
	XOR	BH,BH
	SHL	BX,1
	ADD	AX,[DI][BX]
; added for mode stuff
	TEST	ModeLow,1
	JZ	O3ML3
	MOV	BL,SI1L3
	XOR	BH,BH
	SHL	BX,1
	ADD	AX,[DI][BX]
O3ML3:
	MOV	BL,SO3L3
	XOR	BH,BH
	SHL	BX,1
	ADD	AX,[DI][BX]
	JNS	PosL3
	NEG	AX
	TEST	AX,0F800H	; Check for underflow
	JNZ	UFlowL3
	MOV	BX,AX
	MOV	AL,[MuTbl+BX]
	OR	AL,080H
	OUT	OSRNegPort,AL
	JMP	EndL3

UFlowL3:
	MOV	AL,NegMaxMuVal	; smallest mu-law
	OUT	OSRNegPort,AL
	JMP	EndL3

PosL3:
	TEST	AX,0F800H	; Check for underflow
	JNZ	OFlowL3
	MOV	BX,AX
	MOV	AL,[MuTbl+BX]
	OUT	OSRPosPort,AL
	JMP	EndL3

OFlowL3:
	MOV	AL,MaxMuVal	; largest mu-law
	OUT	OSRPosPort,AL

EndL3:
; LOOP 4

; read 4 words from outbuf 2
	MOV	SI,OutBuf2
	ADD	SI,BP
	MOV	DI,OFFSET SOut2
	MOV	CX,4
	WAIT
	REP MOVSW

; Loop 4, label is xxxL4
	IN	AL,ISRPort
	MOV	BL,AL
	SHL	BX,1
	MOV	BH,SilLocHi
	ADD	DX,[BX]		; add to silence reg.
	MOV	BX,SIGain
	XLATB			; get sample, with gain
	MOV	SI1L4,AL	; sample to input save area

	MOV	CX,O3Delay
O3DL4:
	LOOP	O3DL4

	MOV	DI,SOGain
	MOV	BL,SO1L4
	XOR	BH,BH
	SHL	BX,1
	MOV	AX,[DI][BX]	; first MOV, others ADD
	MOV	BL,SO2L4
	XOR	BH,BH
	SHL	BX,1
	ADD	AX,[DI][BX]
; added for mode stuff
	TEST	ModeLow,1
	JZ	O3ML4
	MOV	BL,SI1L4
	XOR	BH,BH
	SHL	BX,1
	ADD	AX,[DI][BX]
O3ML4:
	MOV	BL,SO3L4
	XOR	BH,BH
	SHL	BX,1
	ADD	AX,[DI][BX]
	JNS	PosL4
	NEG	AX
	TEST	AX,0F800H	; Check for underflow
	JNZ	UFlowL4
	MOV	BX,AX
	MOV	AL,[MuTbl+BX]
	OR	AL,080H
	OUT	OSRNegPort,AL
	JMP	EndL4

UFlowL4:
	MOV	AL,NegMaxMuVal	; smallest mu-law
	OUT	OSRNegPort,AL
	JMP	EndL4

PosL4:
	TEST	AX,0F800H	; Check for underflow
	JNZ	OFlowL4
	MOV	BX,AX
	MOV	AL,[MuTbl+BX]
	OUT	OSRPosPort,AL
	JMP	EndL4

OFlowL4:
	MOV	AL,MaxMuVal	; largest mu-law
	OUT	OSRPosPort,AL

EndL4:
; LOOP 5

; write 4 zeros to outbuf 1
	XOR	AX,AX
	MOV	DI,OutBuf1
	ADD	DI,BP
	MOV	CX,4
	WAIT
	REP STOSW
	CLD

; Loop 5, label is xxxL5
	IN	AL,ISRPort
	MOV	BL,AL
	SHL	BX,1
	MOV	BH,SilLocHi
	ADD	DX,[BX]		; add to silence reg.
	MOV	BX,SIGain
	XLATB			; get sample, with gain
	MOV	SI1L5,AL	; sample to input save area

	MOV	CX,O3Delay
O3DL5:
	LOOP	O3DL5

	MOV	DI,SOGain
	MOV	BL,SO1L5
	XOR	BH,BH
	SHL	BX,1
	MOV	AX,[DI][BX]	; first MOV, others ADD
	MOV	BL,SO2L5
	XOR	BH,BH
	SHL	BX,1
	ADD	AX,[DI][BX]
; added for mode stuff
	TEST	ModeLow,1
	JZ	O3ML5
	MOV	BL,SI1L5
	XOR	BH,BH
	SHL	BX,1
	ADD	AX,[DI][BX]
O3ML5:
	MOV	BL,SO3L5
	XOR	BH,BH
	SHL	BX,1
	ADD	AX,[DI][BX]
	JNS	PosL5
	NEG	AX
	TEST	AX,0F800H	; Check for underflow
	JNZ	UFlowL5
	MOV	BX,AX
	MOV	AL,[MuTbl+BX]
	OR	AL,080H
	OUT	OSRNegPort,AL
	JMP	EndL5

UFlowL5:
	MOV	AL,NegMaxMuVal	; smallest mu-law
	OUT	OSRNegPort,AL
	JMP	EndL5

PosL5:
	TEST	AX,0F800H	; Check for underflow
	JNZ	OFlowL5
	MOV	BX,AX
	MOV	AL,[MuTbl+BX]
	OUT	OSRPosPort,AL
	JMP	EndL5

OFlowL5:
	MOV	AL,MaxMuVal	; largest mu-law
	OUT	OSRPosPort,AL

EndL5:
; LOOP 6

; write 4 zeros to outbuf 2
	XOR	AX,AX
	MOV	DI,OutBuf2
	ADD	DI,BP
	MOV	CX,4
	WAIT
	REP STOSW

; Loop 6, label is xxxL6
	IN	AL,ISRPort
	MOV	BL,AL
	SHL	BX,1
	MOV	BH,SilLocHi
	ADD	DX,[BX]		; add to silence reg.
	MOV	BX,SIGain
	XLATB			; get sample, with gain
	MOV	SI1L6,AL	; sample to input save area

	MOV	CX,O3Delay
O3DL6:
	LOOP	O3DL6

	MOV	DI,SOGain
	MOV	BL,SO1L6
	XOR	BH,BH
	SHL	BX,1
	MOV	AX,[DI][BX]	; first MOV, others ADD
	MOV	BL,SO2L6
	XOR	BH,BH
	SHL	BX,1
	ADD	AX,[DI][BX]
; added for mode stuff
	TEST	ModeLow,1
	JZ	O3ML6
	MOV	BL,SI1L6
	XOR	BH,BH
	SHL	BX,1
	ADD	AX,[DI][BX]
O3ML6:
	MOV	BL,SO3L6
	XOR	BH,BH
	SHL	BX,1
	ADD	AX,[DI][BX]
	JNS	PosL6
	NEG	AX
	TEST	AX,0F800H	; Check for underflow
	JNZ	UFlowL6
	MOV	BX,AX
	MOV	AL,[MuTbl+BX]
	OR	AL,080H
	OUT	OSRNegPort,AL
	JMP	EndL6

UFlowL6:
	MOV	AL,NegMaxMuVal	; smallest mu-law
	OUT	OSRNegPort,AL
	JMP	EndL6

PosL6:
	TEST	AX,0F800H	; Check for underflow
	JNZ	OFlowL6
	MOV	BX,AX
	MOV	AL,[MuTbl+BX]
	OUT	OSRPosPort,AL
	JMP	EndL6

OFlowL6:
	MOV	AL,MaxMuVal	; largest mu-law
	OUT	OSRPosPort,AL

EndL6:
; LOOP 7

; write 4 zeros to outbuf 3
	XOR	AX,AX
	MOV	DI,OutBuf3
	ADD	DI,BP
	MOV	CX,4
	WAIT
	REP STOSW

; Loop 7, label is xxxL7
	IN	AL,ISRPort
	MOV	BL,AL
	SHL	BX,1
	MOV	BH,SilLocHi
	ADD	DX,[BX]		; add to silence reg.
	MOV	BX,SIGain
	XLATB			; get sample, with gain
	MOV	SI1L7,AL	; sample to input save area

	MOV	CX,O3Delay
O3DL7:
	LOOP	O3DL7

	MOV	DI,SOGain
	MOV	BL,SO1L7
	XOR	BH,BH
	SHL	BX,1
	MOV	AX,[DI][BX]	; first MOV, others ADD
	MOV	BL,SO2L7
	XOR	BH,BH
	SHL	BX,1
	ADD	AX,[DI][BX]
; added for mode stuff
	TEST	ModeLow,1
	JZ	O3ML7
	MOV	BL,SI1L7
	XOR	BH,BH
	SHL	BX,1
	ADD	AX,[DI][BX]
O3ML7:
	MOV	BL,SO3L7
	XOR	BH,BH
	SHL	BX,1
	ADD	AX,[DI][BX]
	JNS	PosL7
	NEG	AX
	TEST	AX,0F800H	; Check for underflow
	JNZ	UFlowL7
	MOV	BX,AX
	MOV	AL,[MuTbl+BX]
	OR	AL,080H
	OUT	OSRNegPort,AL
	JMP	EndL7

UFlowL7:
	MOV	AL,NegMaxMuVal	; smallest mu-law
	OUT	OSRNegPort,AL
	JMP	EndL7

PosL7:
	TEST	AX,0F800H	; Check for underflow
	JNZ	OFlowL7
	MOV	BX,AX
	MOV	AL,[MuTbl+BX]
	OUT	OSRPosPort,AL
	JMP	EndL7

OFlowL7:
	MOV	AL,MaxMuVal	; largest mu-law
	OUT	OSRPosPort,AL

EndL7:
; now complete the work
	ADD	BP,8
	CMP	BP,LastIL	; 320
	JGE	AllDoneO3I1
	CMP	BP,HalfIL	; 160
	JE	HalfDoneO3I1
	JMP	MidPktO3I1
	
AllDoneO3I1:
	XOR	BP,BP
HalfDoneO3I1:
	JMP	EndPktO3I1

; Loop Out 2 In 2
; There are 8 copies of the basic code ( 8 x loop unrolled) because different
; things happen at the beginning of each loop

; Loop 0
; 	write sample pointer (mid packet only)
; 	store SilVal1  (end of packet only)
; 	store SilVal2
; 	store sample pointer
; Loop 1 	Write InBuf1
; Loop 2 	write InBuf2
; Loop 3 	Read OutBuf1
; Loop 4 	Read OutBuf2
; Loop 5 	write zeros in OutBuf1
;		CLD
; Loop 6 	write zeros in OutBuf2
; Loop 7 	read In1Gain
;		read In2Gain
; 	read mode bits

LoopO2I2:
; set up segment registers
	MOV	AX,0
	MOV	DS,AX
	MOV	ES,AX
	MOV	SS,AX
; initialize registers for loop
	MOV	SP,SPIN		; probably don't need a stack but...
	XOR	DX,DX		; initialize silence register
	XOR	BP,BP		; initialize buffer pointer
	CLD			; string ops increment
	JMP	MidPktO2I2
; read InGain and OutGain
; write BufBtr
; write SilVal on wraparound

MidPktO2I2:
	MOV	SI,BufPtr
	WAIT
	MOV	[SI],BP		; store pointer (was in BP)
; wait 8 microseconds
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	JMP	StartL0O2I2

EndPktO2I2:
	MOV	SI,OFFSET SilVal1
	MOV	DI,Sil1Val
	WAIT
	MOVSW			; store SilVal1
	MOVSW			; store SilVal2
	MOV	[SI],BP		; store pointer (was in BP)
	MOV	SilVal1,0
	MOV	SilVal2,0

StartL0O2I2:
	MOV	AL,SO2L0	; output for TS13
	OR	AL,AL
	JS	Neg1L0
	OUT	OSRPosPort,AL
	JMP	In1L0
Neg1L0:
	OUT	OSRNegPort,AL
In1L0:
	IN	AL,ISRPort	; input from TS1
	MOV	CL,AL
	SHL	CX,1
	MOV	CH,SilLocHi
	MOV	BX,SI1Gain
	XLATB			; get sample, with gain
	MOV	SI1L0,AL	; sample to input save area
	MOV	AX,SilVal1
	MOV	BX,CX
	ADD	AX,[BX]		; add to silence reg.
	MOV	SilVal1,AX
; halfway
	MOV	CX,O2Delay
MidL0:
	LOOP	MidL0
	
	MOV	AL,SO1L0	; output for TS1
	OR	AL,AL
	JS	Neg2L0
	OUT	OSRPosPort,AL
	JMP	In2L0
Neg2L0:
	OUT	OSRNegPort,AL
In2L0:
	IN	AL,ISRPort	; Input from TS13
	MOV	CL,AL
	SHL	CX,1
	MOV	CH,SilLocHi
	MOV	BX,SI2Gain
	XLATB			; get sample, with gain
	MOV	SI2L0,AL	; sample to input save area
	MOV	AX,SilVal2
	MOV	BX,CX
	ADD	AX,[BX]		; add to silence reg.
	MOV	SilVal2,AX
L2EndL0:

; move 4 words from input save area to shared memory
	MOV	SI,OFFSET SIn1
	MOV	DI,InBuf1
	ADD	DI,BP
	MOV	CX,4
	WAIT
	REP MOVSW

StartL1:
; Loop 1, label is xxxL1
	MOV	AL,SO2L1	; output for TS13
	OR	AL,AL
	JS	Neg1L1
	OUT	OSRPosPort,AL
	JMP	In1L1
Neg1L1:
	OUT	OSRNegPort,AL
In1L1:
	IN	AL,ISRPort	; input from TS1
	MOV	CL,AL
	SHL	CX,1
	MOV	CH,SilLocHi
	MOV	BX,SI1Gain
	XLATB			; get sample, with gain
	MOV	SI1L1,AL	; sample to input save area
	MOV	AX,SilVal1
	MOV	BX,CX
	ADD	AX,[BX]		; add to silence reg.
	MOV	SilVal1,AX
; halfway
	MOV	CX,O2Delay
MidL1:
	LOOP	MidL1
	
	MOV	AL,SO1L1	; output for TS1
	OR	AL,AL
	JS	Neg2L1
	OUT	OSRPosPort,AL
	JMP	In2L1
Neg2L1:
	OUT	OSRNegPort,AL
In2L1:
	IN	AL,ISRPort	; Input from TS13
	MOV	CL,AL
	SHL	CX,1
	MOV	CH,SilLocHi
	MOV	BX,SI2Gain
	XLATB			; get sample, with gain
	MOV	SI2L1,AL	; sample to input save area
	MOV	AX,SilVal2
	MOV	BX,CX
	ADD	AX,[BX]		; add to silence reg.
	MOV	SilVal2,AX

L2EndL1:


; move 4 words from input (2) save area to shared memory
	MOV	SI,OFFSET SIn2
	MOV	DI,InBuf2
	ADD	DI,BP
	MOV	CX,4
	WAIT
	REP MOVSW

StartL2:
; Loop 2, label is xxxL2
	MOV	AL,SO2L2	; output for TS13
	OR	AL,AL
	JS	Neg1L2
	OUT	OSRPosPort,AL
	JMP	In1L2
Neg1L2:
	OUT	OSRNegPort,AL
In1L2:
	IN	AL,ISRPort	; input from TS1
	MOV	CL,AL
	SHL	CX,1
	MOV	CH,SilLocHi
	MOV	BX,SI1Gain
	XLATB			; get sample, with gain
	MOV	SI1L2,AL	; sample to input save area
	MOV	AX,SilVal1
	MOV	BX,CX
	ADD	AX,[BX]		; add to silence reg.
	MOV	SilVal1,AX
; halfway
	MOV	CX,O2Delay
MidL2:
	LOOP	MidL2
	
	MOV	AL,SO1L2	; output for TS1
	OR	AL,AL
	JS	Neg2L2
	OUT	OSRPosPort,AL
	JMP	In2L2
Neg2L2:
	OUT	OSRNegPort,AL
In2L2:
	IN	AL,ISRPort	; Input from TS13
	MOV	CL,AL
	SHL	CX,1
	MOV	CH,SilLocHi
	MOV	BX,SI2Gain
	XLATB			; get sample, with gain
	MOV	SI2L2,AL	; sample to input save area
	MOV	AX,SilVal2
	MOV	BX,CX
	ADD	AX,[BX]		; add to silence reg.
	MOV	SilVal2,AX
L2EndL2:


; read 4 words from outbuf 1
; if mode bit 2 is set, read from inbuf
	TEST	ModeLow,2
	JNZ	ModeL3
	MOV	SI,OutBuf1
	JMP	ShrL3
ModeL3:
	MOV	SI,InBuf1
ShrL3:
	ADD	SI,BP
	MOV	DI,OFFSET SOut1
	MOV	CX,4
	WAIT
	REP MOVSW

StartL3:
; Loop 3, label is xxxL3
	MOV	AL,SO2L3		; output for TS13
	OR	AL,AL
	JS	Neg1L3
	OUT	OSRPosPort,AL
	JMP	In1L3
Neg1L3:
	OUT	OSRNegPort,AL
In1L3:
	IN	AL,ISRPort		; input from TS1
	MOV	CL,AL
	SHL	CX,1
	MOV	CH,SilLocHi
	MOV	BX,SI1Gain
	XLATB			; get sample, with gain
	MOV	SI1L3,AL		; sample to input save area
	MOV	AX,SilVal1
	MOV	BX,CX
	ADD	AX,[BX]		; add to silence reg.
	MOV	SilVal1,AX
; halfway
	MOV	CX,O2Delay
MidL3:
	LOOP	MidL3
	
	MOV	AL,SO1L3	; output for TS1
	OR	AL,AL
	JS	Neg2L3
	OUT	OSRPosPort,AL
	JMP	In2L3
Neg2L3:
	OUT	OSRNegPort,AL
In2L3:
	IN	AL,ISRPort	; Input from TS13
	MOV	CL,AL
	SHL	CX,1
	MOV	CH,SilLocHi
	MOV	BX,SI2Gain
	XLATB			; get sample, with gain
	MOV	SI2L3,AL	; sample to input save area
	MOV	AX,SilVal2
	MOV	BX,CX
	ADD	AX,[BX]		; add to silence reg.
	MOV	SilVal2,AX
L2EndL3:

; read 4 words from outbuf 2
; if mode bit 2 is set, read from inbuf
	TEST	ModeLow,2
	JNZ	ModeL4
	MOV	SI,OutBuf2
	JMP	ShrL4
ModeL4:
	MOV	SI,InBuf2
ShrL4:
	ADD	SI,BP
	MOV	DI,OFFSET SOut2
	MOV	CX,4
	WAIT
	REP MOVSW
StartL4:
; Loop 4, label is xxxL4
	MOV	AL,SO2L4	; output for TS13
	OR	AL,AL
	JS	Neg1L4
	OUT	OSRPosPort,AL
	JMP	In1L4
Neg1L4:
	OUT	OSRNegPort,AL
In1L4:
	IN	AL,ISRPort	; input from TS1
	MOV	CL,AL
	SHL	CX,1
	MOV	CH,SilLocHi
	MOV	BX,SI1Gain
	XLATB			; get sample, with gain
	MOV	SI1L4,AL	; sample to input save area
	MOV	AX,SilVal1
	MOV	BX,CX
	ADD	AX,[BX]		; add to silence reg.
	MOV	SilVal1,AX
; halfway
	MOV	CX,O2Delay
MidL4:
	LOOP	MidL4
	
	MOV	AL,SO1L4	; output for TS1
	OR	AL,AL
	JS	Neg2L4
	OUT	OSRPosPort,AL
	JMP	In2L4
Neg2L4:
	OUT	OSRNegPort,AL
In2L4:
	IN	AL,ISRPort	; Input from TS13
	MOV	CL,AL
	SHL	CX,1
	MOV	CH,SilLocHi
	MOV	BX,SI2Gain
	XLATB			; get sample, with gain
	MOV	SI2L4,AL	; sample to input save area
	MOV	AX,SilVal2
	MOV	BX,CX
	ADD	AX,[BX]		; add to silence reg.
	MOV	SilVal2,AX
L2EndL4:

; write 4 zeros to outbuf 1
	XOR	AX,AX
	MOV	DI,OutBuf1
	ADD	DI,BP
	MOV	CX,4
	WAIT
	REP STOSW
	CLD

StartL5:
; Loop 5, label is xxxL5
	MOV	AL,SO2L5	; output for TS13
	OR	AL,AL
	JS	Neg1L5
	OUT	OSRPosPort,AL
	JMP	In1L5
Neg1L5:
	OUT	OSRNegPort,AL
In1L5:
	IN	AL,ISRPort	; input from TS1
	MOV	CL,AL
	SHL	CX,1
	MOV	CH,SilLocHi
	MOV	BX,SI1Gain
	XLATB			; get sample, with gain
	MOV	SI1L5,AL	; sample to input save area
	MOV	AX,SilVal1
	MOV	BX,CX
	ADD	AX,[BX]		; add to silence reg.
	MOV	SilVal1,AX
; halfway
	MOV	CX,O2Delay
MidL5:
	LOOP	MidL5
	
	MOV	AL,SO1L5	; output for TS1
	OR	AL,AL
	JS	Neg2L5
	OUT	OSRPosPort,AL
	JMP	In2L5
Neg2L5:
	OUT	OSRNegPort,AL
In2L5:
	IN	AL,ISRPort	; Input from TS13
	MOV	CL,AL
	SHL	CX,1
	MOV	CH,SilLocHi
	MOV	BX,SI2Gain
	XLATB			; get sample, with gain
	MOV	SI2L5,AL	; sample to input save area
	MOV	AX,SilVal2
	MOV	BX,CX
	ADD	AX,[BX]		; add to silence reg.
	MOV	SilVal2,AX
L2EndL5:

; write 4 zeros to outbuf 2
	XOR	AX,AX
	MOV	DI,OutBuf2
	ADD	DI,BP
	MOV	CX,4
	WAIT
	REP STOSW

StartL6:
; Loop 6, label is xxxL6
	MOV	AL,SO2L6	; output for TS13
	OR	AL,AL
	JS	Neg1L6
	OUT	OSRPosPort,AL
	JMP	In1L6
Neg1L6:
	OUT	OSRNegPort,AL
In1L6:
	IN	AL,ISRPort	; input from TS1
	MOV	CL,AL
	SHL	CX,1
	MOV	CH,SilLocHi
	MOV	BX,SI1Gain
	XLATB			; get sample, with gain
	MOV	SI1L6,AL	; sample to input save area
	MOV	AX,SilVal1
	MOV	BX,CX
	ADD	AX,[BX]		; add to silence reg.
	MOV	SilVal1,AX
; halfway
	MOV	CX,O2Delay
MidL6:
	LOOP	MidL6
	
	MOV	AL,SO1L6	; output for TS1
	OR	AL,AL
	JS	Neg2L6
	OUT	OSRPosPort,AL
	JMP	In2L6
Neg2L6:
	OUT	OSRNegPort,AL
In2L6:
	IN	AL,ISRPort	; Input from TS13
	MOV	CL,AL
	SHL	CX,1
	MOV	CH,SilLocHi
	MOV	BX,SI2Gain
	XLATB			; get sample, with gain
	MOV	SI2L6,AL	; sample to input save area
	MOV	AX,SilVal2
	MOV	BX,CX
	ADD	AX,[BX]		; add to silence reg.
	MOV	SilVal2,AX
L2EndL6:

; save pointer
	MOV	SI,ModeFlag
	MOV	DI,OFFSET SI2Gain
	WAIT
	LODSW			; read ModeFlag
	MOV	ModeBits,AX
	MOVSW			; read In2Gain
	MOVSW			; read In1Gain
; wait 8 microseconds
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
StartL7:
; Loop 7, label is xxxL7
	MOV	AL,SO2L7	; output for TS13
	OR	AL,AL
	JS	Neg1L7
	OUT	OSRPosPort,AL
	JMP	In1L7
Neg1L7:
	OUT	OSRNegPort,AL
In1L7:
	IN	AL,ISRPort	; input from TS1
	MOV	CL,AL
	SHL	CX,1
	MOV	CH,SilLocHi
	MOV	BX,SI1Gain
	XLATB			; get sample, with gain
	MOV	SI1L7,AL	; sample to input save area
	MOV	AX,SilVal1
	MOV	BX,CX
	ADD	AX,[BX]		; add to silence reg.
	MOV	SilVal1,AX
; halfway
	MOV	CX,O2Delay
MidL7:
	LOOP	MidL7
	
	MOV	AL,SO1L7	; output for TS1
	OR	AL,AL
	JS	Neg2L7
	OUT	OSRPosPort,AL
	JMP	In2L7
Neg2L7:
	OUT	OSRNegPort,AL
In2L7:
	IN	AL,ISRPort	; Input from TS13
	MOV	CL,AL
	SHL	CX,1
	MOV	CH,SilLocHi
	MOV	BX,SI2Gain
	XLATB			; get sample, with gain
	MOV	SI2L7,AL	; sample to input save area
	MOV	AX,SilVal2
	MOV	BX,CX
	ADD	AX,[BX]		; add to silence reg.
	MOV	SilVal2,AX
L2EndL7:
; now complete the work
	ADD	BP,8
	CMP	BP,LastIL	; 320
	JGE	AllDoneO2I2
	CMP	BP,HalfIL	; 160
	JE	HalfDoneO2I2
	JMP	MidPktO2I2
	
AllDoneO2I2:
	XOR	BP,BP
HalfDoneO2I2:
	JMP	EndPktO2I2

C←CODE	ENDS
	END