; LarkSlave.dsm
; Code for Lark Slave processor
; L. Stewart June 29, 1982  3:59 PM

; 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
; 	Read OutBuf1
; Loop 2
; 	Read OutBuf2
; Loop 3
; 	Read OutBuf3
; Loop 4
; 	write InBuf
; Loop 5
; 	write zeros in OutBuf1
;	CLD
; Loop 6
; 	write zeros in OutBuf2
; Loop 7
; 	write zeros in OutBuf3

; 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
InBuf	EQU	0C000H
OutBuf1	EQU	0C200H
OutBuf2	EQU	0C400H
OutBuf3	EQU	0C600H
InGain	EQU	0C800H
OutGain	EQU	0C802H
BufPtr	EQU	0C804H
SilVal	EQU	0C806H

; constants for testing
LastIL	EQU	320
HalfIL	EQU	160

; addresses in local memory
SPIN	EQU	03FF0H		; 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

C←CODE	SEGMENT

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

C←DATA	SEGMENT

; save area for samples being read or writted this loop
TS1In	DB	?
TS1Out	DB	?
TS13In	DB	?
TS13Out	DB	?
; Save area for OutBuf1
; This table is rotated by 1 because the block of 8 samples is read
; from the shared memory during Loop 1
SOut1	LABEL	BYTE
SO1L1	DB	?
SO1L2	DB	?
SO1L3	DB	?
SO1L4	DB	?
SO1L5	DB	?
SO1L6	DB	?
SO1L7	DB	?
SO1L0	DB	?

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

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

; Save area for InBuf
; This table is rotated by 4 because the block of 8 samples is written
; from the shared memory during Loop 4
SIn	LABEL	BYTE
SIL4	DB	?
SIL5	DB	?
SIL6	DB	?
SIL7	DB	?
SIL0	DB	?
SIL1	DB	?
SIL2	DB	?
SIL3	DB	?

; Save area for input and output gain addresses
SIGain	DW	?
SOGain	DW	?

C←DATA	ENDS

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

Init:
; 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

; read InGain and OutGain
; write BufBtr
; write SilVal on wraparound

MidPkt:
	MOV	SI,InGain
	MOV	DI,OFFSET SIGain
	WAIT
	MOVSW			; read InGain
	MOVSW			; read OutGain
	MOV	[SI],BP		; store pointer (was in BP)
	JMP	StartL0

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

StartL0:
; Loop 0, label is xxxL0
	MOV	BX,TS1IGain
	IN	AL,ISRPort	; must be after end of TS1
	XLATB
	MOV	IB1,AL
	MOV	BX,TS13OGain
	MOV	AL,OTS1
	XLATB
	OUT	OSRPort,AL

; wait for TSN

	MOV	BX,TS1IGain
	IN	AL,ISRPort	; must be after end of TS1
	XLATB
	MOV	IB1,AL
	MOV	BX,TS13OGain
	MOV	AL,OTS1
	XLATB
	OUT	OSRPort,AL
EndL0:

; LOOP 1

; read 4 words from outbuf 1
	MOV	SI,OutBuf1
	ADD	SI,BP
	MOV	DI,OFFSET SOut1
	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	SIL1,AL		; sample to input save area

	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP

	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP

	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]
	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 2
	MOV	SI,OutBuf2
	ADD	SI,BP
	MOV	DI,OFFSET SOut2
	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	SIL2,AL		; sample to input save area

	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP

	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP

	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]
	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 3
	MOV	SI,OutBuf3
	ADD	SI,BP
	MOV	DI,OFFSET SOut3
	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	SIL3,AL		; sample to input save area

	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP

	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP

	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]
	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

; move 4 words from input save area to shared memory
	MOV	SI,OFFSET SIn
	MOV	DI,InBuf
	ADD	DI,BP
	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	SIL4,AL		; sample to input save area

	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP

	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP

	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]
	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	SIL5,AL		; sample to input save area

	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP

	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP

	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]
	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	SIL6,AL		; sample to input save area

	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP

	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP

	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]
	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	SIL7,AL		; sample to input save area

	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP

	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP

	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]
	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	AllDone
	CMP	BP,HalfIL	; 160
	JE	HalfDone
	JMP	MidPkt
	
AllDone:
	XOR	BP,BP
HalfDone:
	JMP	EndPkt

C←CODE	ENDS
	END