; LarkSlave.dsm
; Ram Code for Lark Slave processor
; L. Stewart September 8, 1983  6:02 PM

; This file had better closely track LarkSlave.dsm in
; the constants and variable declarations!


; 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 2 (was 5) because the
; block of 8 samples is read
; from the shared memory during Loop 2 (was 5)
SOut3	LABEL	BYTE
SO3L2	DB	?
SO3L3	DB	?
SO3L4	DB	?
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	?

	DW	0
	CALL	←monEnd
←monEnd	DW 0
	PUBLIC	←monEnd

C←DATA	ENDS

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

; This code is at loc 2000

; This is a repaired copy of Loop O3I1 found
;    in the Slave EPROM

; The bug was that the variable declarations require that
; output buffer 3 be read from shared memory during Loop 5
; but the program was reading it during Loop 2.
; Fix 1:  Swap the Loop 5 and Loop 2 activities
; Fix 2:  Rotate the SOut1 declaration to match Loop 2

; Fix 2 seems simpler

; 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

	DW	0
	CALL	←monEndCode
←monEndCode	DW 0
	PUBLIC	←monEndCode

C←CODE	ENDS
	END