;Compile into a .COM file
TITLE   CGA test program
.MODEL TINY
.8086           ;Use 8086 code
.CODE
.STARTUP

START:
	MOV     DX,OFFSET MESSAGE       ;Print my name
	MOV     AH,09h
	INT     21h
	
	MOV     AH,4
	MOV     BH,60h
	CALL    OUT_DATA
	MOV     BH,80h
	CALL    OUT_DATA
	MOV     DX,0388h
	IN      AL,DX
	MOV     REG1,AL
	MOV     AH,2
	MOV     BH,0FFh
	CALL    OUT_DATA
	MOV     AH,4
	MOV     BH,21h
	CALL    OUT_DATA
	HLT
	IN      AL,DX
	MOV     REG2,AL
	MOV     AH,4
	MOV     BH,60h
	CALL    OUT_DATA
	MOV     BH,80h
	CALL    OUT_DATA
	AND     REG1,0E0H
	AND     REG2,0E0H
	CMP     REG1,0
	JNE     NO_CARD
	CMP     REG2,0C0H
	JNE     NO_CARD
				;The following loop does a simple
				;reset of the sound card by outputting
				;a 0 to all of the registers
	MOV     BX,00F5h
LOOP2:
	MOV     AH,CL
	CALL    OUT_DATA
	DEC     BL
	TEST    BL,BL
	JNZ     LOOP2
	MOV     SI,0
				;This loop reads the data from DATA
				;and outputs it to the soundcard.
LOOP1:
	MOV     AH,BYTE PTR DATA[SI]
	INC     SI
	MOV     BH,BYTE PTR DATA[SI]
	INC     SI
	CMP     AH,0FFh
	JE      END_PROG
	CALL    OUT_DATA
	JMP     LOOP1
END_PROG:
	MOV     DX,OFFSET KEYPRESS
	MOV     AH,09H
	INT     21h
	MOV     AH,07h
	INT     21h             ;Wait for a keypress
	MOV     AH,0B0h
	MOV     BH,11h
	CALL    OUT_DATA
	MOV     AX,4C00H         ; Send exit code to dos
	INT     21H             ; Send command to DOS
NO_CARD:
	MOV     DX,OFFSET NO_ADLIB
	MOV     AH,09H
	INT     21h
	MOV     AX,4C01h
	INT     21h

OUT_DATA        PROC    NEAR
	;Sends byte in BH to port specified in AH and waits as neccessary
	PUSH    CX
	MOV     DX,0388h
	MOV     AL,AH
	OUT     DX,AL
	MOV     CX,6
	CALL    CYCLE_WAIT
	INC	DX
	MOV     AL,BH
	OUT     DX,AL
	MOV     CX,35
	CALL    CYCLE_WAIT
	POP     CX
	RET
OUT_DATA        ENDP

CYCLE_WAIT      PROC    NEAR
	;Reads from the FM synth card a number of times
	;specified in CX.  This is necessary because the chip
	;needs a delay.  CX=6 if you want to wait after writing to the
	;register port (12 cyles) and CX=35 to wait after writing to the
	;data port.

	MOV     DX,0388h
W12LOOP:
	IN      AL,DX
	DEC     CX
	TEST    CX,CX
	JNZ     W12LOOP
	RET

CYCLE_WAIT      ENDP

AUTHOR          DB      "Made by Dennis Katsonis.",0ah,0dh,24h
MESSAGE         DB      09h,"****   FM Synthesis Demonstration   ****",0ah,0dh,024h
DATA            DB      20h,01h,40h,10h,60h,0f0h,80h,77h,0A0h,98h,23h,01h,43h,0,63h,0f0h,83h,77h,0b0h,31h,0ffh,0ffh
KEYPRESS        DB      "Press any key to exit program and stop the sounds.",0ah,0dh,24h
NO_ADLIB        DB      "No Adlib compatible card detected!",0ah,0dh,24h
REG1            DB      ?
REG2            DB      ?

END
