;	RXINT:
;	version 1.1
;	2/2/86
;
;	This is the main receive interrupt.
;	It is called when the DART receives data.
;	This version supports carry-over (running) status bytes
;	as well as a translate table.
;

    DSEG

; These are C's globals
PUBLIC r_segment_
PUBLIC ptr_
PUBLIC end_
PUBLIC destbyte_
PUBLIC clsb_
PUBLIC cmsb_
PUBLIC stop_
PUBLIC LAST_STAT_
PUBLIC C_O_F_   		; status carry-over flag
PUBLIC clk_type_		; 0=internal,  1=external
PUBLIC counter_dec_
PUBLIC in_filt_			; the MIDI input filter
				; bit:
				;   0 = Note on filt
				;   1 = Note off filt
				;   2 = Prog change filt
				;   3 = Channel after-touch
				;   4 = Pitch wheel
				;   5 = All other controllers
				;   6 = Key after-touch

    CSEG       ; ALL CODE

    PUBLIC rxint_

rxint_:
    STI				; interrupts back on
    PUSH AX
    MOV AL,0B9H 		; shut off counter interrupt
    OUT 021H,AL
    PUSH BX
    PUSH DX
    PUSH ES
    PUSH DS
    MOV AX,0  			; this will be new value for the
				; DS so we can access the OLD DS
    MOV DS,AX
    MOV BX,WORD [04FAH] 	; put new DS in BX
    MOV DS,BX           	; put new DS in DS
    MOV AX,r_segment_
    MOV ES,AX           	; set buffer segment

sst:
    MOV DX,0FFA2H       	; midi stat
    MOV AL,1            	; rd register 1
    OUT DX,AL
    IN AL,DX            	; RD reg 1
    AND AL,32           	; Rx overrun error?
    JNZ finished        	; if so, than we're REALLY done!
_st:                    	; jumped to by _iret if another char is available
    IN AL,DX            	; read status register
    AND AL,1            	; Rx char?
    JZ _iret            	; if not, return
    MOV DX,0FFA0H       	; MIDI data
    IN AL,DX            	; now let's read it
    MOV DL,AL           	; store in DL for later
    CMP AL,0F8H         	; timing clock?
    JNZ C1              	; if not, check for stop
    MOV DL,counter_dec_		; get amount to decrement counter
    MOV DH,0			; we'll do a word subtract
    MOV AL,clsb_		; get lsb 
    MOV AH,cmsb_		; get msb
    SUB AX,DX			; dcr word
    MOV clsb_,AL		; store lsb
    MOV cmsb_,AH		; store msb
    JMP _iret           	; if is, all done

C1:
    CMP AL,0FCH         	; MIDI Stop?
    JNZ C4              	; if not, continue
    MOV BYTE stop_,1    	; else, set stop byte
    JMP _iret           	; and return
C4:
    AND AL,0F0H         	; strip off top 4
    CMP AL,0F0H         	; running status?
    JZ _iret            	; if so, we're done
    MOV BYTE AL,destbyte_	; get destbyte
    CMP AL,0FFH         	; shall we continue?
    JZ _iret            	; if not, then we're done
    MOV BL,AL           	; keep for later
    AND AL,0F0H         	; strip off top four
    JZ _newmsg          	; first byte of a new message - What a revelation!
contzz:                 	; branch point from carry-over status
    CMP AL,010H         	; Note ON?
    JZ _nton            	; yes?
    CMP AL,020H         	; Note OFF?
    JZ _noff            	; yes?
    CMP AL,070H			; Poly key pres?
    JZ _keypres
    CMP AL,040H         	; Bender?
    JZ _bender          	; yes?
    CMP AL,050H         	; Control Change?
    JZ _cchan           	; yes?
    CMP AL,060H         	; Channel Velocity?
    JZ _cvel			; For now, throw away channel velocity
    CMP AL,030H         	; Prog Change?
    JZ _pchan           	; yes?
    JMP _iret			; This would fall through for FILTed out codes

        ; this routine (newmsg) processes the first byte of a given
        ; message, and also decides if it is an important message

_newmsg:                ; it's a new message
    MOV AL,DL			; retrieve
    AND AL,080H
    MOV AL,DL
    MOV BYTE C_O_F_,0		; no carry-over
    JNZ contxx			; check for MIDI carry-over stat.
    MOV BYTE AL,LAST_STAT_	; get previous status byte
    MOV BYTE C_O_F_,0FFH 	; carry-over status
contxx:
    MOV BYTE destbyte_,0	; this is default in case code isn't
				; supported or is filtered out
    MOV CL,in_filt_		; this is input filter
    AND AL,0F0H         	; strip off channel info.
    MOV LAST_STAT_,AL   	; save new last stat
    CMP AL,090H         	; Note ON?
    JZ _nnon            	; yes?
    CMP AL,080H         	; Note OFF?
    JZ _nnoff           	; yes?
    CMP AL,0A0H			; Poly key press?
    JZ _nkeypres		; yes?
    CMP AL,0E0H         	; Pitch Wheel
    JZ _npwch           	; yes?
    CMP AL,0B0H         	; Control Change?
    JZ _ncchan          	; yes?
    CMP AL,0C0H         	; Prog. Chan?
    JZ _npchan          	; yes?
    CMP AL,0D0H         	; Channel Velocity?
    JZ _nchanv			; yes?
    JMP _iret           	; otherwise, it must be a code we don't support

_nnon:                  ; first byte of a note on just came in
    AND CL,1			; keep note-ons?
    JZ _iret			; no, then all done.
    CALL _stime			; store present time
    MOV BYTE ES:[BX],0		; put 0 at *ptr - I.D. code for note on/off
    MOV BYTE destbyte_,011H	; note on in dest byte
    JMP _cco            	; check carry-over

_nnoff:                 ; first byte of note off just came in
    AND CL,2			; keep note-offs?
    JZ _iret			; no, then all done
    CALL _stime         	; same as _nnon (above)
    MOV BYTE ES:[BX],0		; I.D.
    MOV BYTE destbyte_,021H	; note off in destbyte
    JMP _cco            	; check carry-over

_ncchan:                ; first byte of control change
    AND CL,32			; keep control changes?
    JZ _iret			; no
    CALL _stime
    MOV BYTE ES:[BX],0C0H	; I.D.
    MOV BYTE destbyte_,051H	; cchan in destbyte
    JMP _cco            	; check carry-over

_npchan:                ; 1st byte of program change
    AND CL,4			; keep prog. changes?
    JZ _iret
    CALL _stime
    MOV BYTE ES:[BX],040H	; I.D.
    MOV BYTE destbyte_,031H	; prog chan in destbyte
    JMP _cco            	; check carry-over

_nchanv:                ; 1st byte of Channel pressure
    AND CL,8			; keep channel pressure?
    JZ _iret
    CALL _stime
    MOV BYTE ES:[BX],041H       ; I.D.
    MOV BYTE destbyte_,061H	; chan vel in dbyte
    JMP _cco			; check carry-over

_nkeypres:		; 1st byte of Poly. key pres.
    AND CL,64			; keep poly. key pres?
    JZ _iret
    CALL _stime
    MOV BYTE ES:[BX],060H       ; I.D.
    MOV BYTE destbyte_,071H	; chan vel in dbyte
    JMP _cco			; check carry-over

_npwch:			; first byte of pitch wheel change
    AND CL,16			; keep pitch wheel?
    JZ _iret
    CALL _stime
    MOV BYTE ES:[BX],080H	; I.D.
    MOV BYTE destbyte_,041H	; pitch wheel in dbyte
    JMP _cco			; check carry-over

_cco:   ; check carry over flag
    MOV BYTE AL,C_O_F_		; get carry over flag
    OR AL,AL            	; set flags
    JZ _iret
    MOV BYTE AL,destbyte_
    MOV BL,AL
    AND AL,0F0H
    JMP contzz          	; carry over

        ; now for the routines that are called while a message is in
        ; progress:

_nton:                  	; note on processing routine
    AND BL,1            	; BL still has destbyte in it
    MOV WORD BX,ptr_    	; get pointer
    JZ _ntonvel         	; must be a 2, so go and save velocity
    OR DL,080H          	; set top bit of note
    ADD BX,3            	; inr pointer to note
    MOV BYTE ES:[BX],DL         ; store it
    INC BYTE destbyte_  	; inr for velocity, which will come in next
    JMP _iret           	; all done
_ntonvel:               	; must be a velocity byte
    SHR DL,1            	; shift velocity byte one to the right
    OR BYTE ES:[BX],DL          ; OR it in
    MOV BYTE destbyte_,0	; next byte will be a newmsg
    ADD WORD ptr_,4     	; inr ptr
    JMP _iret			; all done

_noff:                  	; note off processing routine
    AND BL,1            	; BL still has destbyte in it
    MOV WORD BX,ptr_    	; get pointer into buff
    JZ _ntoffvel        	; if destbyte=2, then it must be a velocity
    ADD BX,3            	; inr to where we'll store the note
    MOV BYTE ES:[BX],DL		; store note; top bit should already be 0
    INC BYTE destbyte_  	; inr destbyte for velocity
    JMP _iret           	; all done
_ntoffvel:              	; must be a velocity byte
    SHR DL,1			; shift DL logically right 1
    OR BYTE ES:[BX],DL		; OR it in
    MOV BYTE destbyte_,0	; next byte will be a newmsg
    ADD WORD ptr_,4     	; now _ptr points to the next message spot
    JMP _iret           	; all done

_pchan:                 	; program change (new program)
    MOV WORD BX,ptr_    	; get pointer; no need to check byte number
                        	; because only two bytes are transmitted
    ADD BX,3            	; this is where we'll store the new prog. #
    MOV BYTE ES:[BX],DL         ; store data
    MOV BYTE destbyte_,0	; reset to newmsg
    ADD WORD ptr_,4     	; inr to pstn. of next massage
    JMP _iret			; all done

_bender:                	; store bender data
    AND BL,1            	; first data byte?
    JZ _bmsb            	; if not, than go and store the MSB
    INC BYTE destbyte_  	; inr for next pass
    JMP _iret           	; all done
_bmsb:                  	; store MSB of bender
    SHR DL,1            	; shift DL down 1
    MOV WORD BX,ptr_    	; get ptr
    OR BYTE ES:[BX],DL		; OR in top 6 of MSB of bender
    ADD WORD ptr_,3     	; inr pointer to next message
    MOV BYTE destbyte_,0	; next message will newmsg
    JMP _iret			; all done


_cchan:                 	; control change
    AND BL,1            	; control #?
    MOV WORD BX,ptr_    	; get ptr_
    JNZ _cnum           	; if input is control #, then save it
    ADD BX,4            	; this is where we'll store the control value
    MOV BYTE ES:[BX],DL         ; store control value
    MOV BYTE destbyte_,0	; next byte will newmsg
    ADD WORD ptr_,5     	; inr to next message location
    JMP _iret           	; all done
_cnum:                  	; number
    ADD BX,3            	; address of control number
    MOV BYTE ES:[BX],DL 	; store control number
    INC BYTE destbyte_  	; next byte will be control value
    JMP _iret           	; all done

_cvel:                  	; channel velocity
    MOV WORD BX,ptr_    	; load BX w/pointer
    MOV BYTE ES:[BX+3],DL	; store velocity
    ADD WORD ptr_,4		; inr to next message pstn.
    MOV BYTE destbyte_,0	; next byte will be new msg
    JMP _iret           	; all done

_keypres:			; poly. key pressure
    AND BL,1 			; amount?
    MOV WORD BX,ptr_
    JZ _storepres		; store key pressure
    ADD BX,3			; this is where to store the note num.
    MOV BYTE ES:[BX],DL		; store it
    INC BYTE destbyte_		; next byte will be val.
    JMP _iret
_storepres:			; store key pressure
    SHR DL,1
    SHR DL,1			; shift DL right 2 (/4)
    OR ES:[BX],DL		; OR it in
    MOV BYTE destbyte_,0	; next byte new message
    JMP _iret			; all done


_stime:                 	; routine to read the PIT and store the results
                        	; in the buffer
    PUSH DX             	; preserve data
    MOV WORD BX,ptr_    	; get pointer
    MOV AL,clk_type_		; get clk type (0=int)
    OR AL,AL			; set flags
    JNZ ext_clk			; is clk_type=ext_clk??
    MOV AL,64           	; counter latching operation
    MOV DX,0FFA7H       	; counter stat
    OUT DX,AL           	; out to PIT
    NOP                 	; stall for time
    NOP
    MOV DX,0FFA5H       	; counter 2
    IN AL,DX            	; read _clsb
    MOV BYTE ES:[BX+1],AL	; store in buffer
    NOP
    NOP
    IN AL,DX            	; read _cmsb
    MOV BYTE ES:[BX+2],AL
    POP DX              	; restore data
    RET

ext_clk:		; timing clock from MIDI
    MOV DL,clsb_
    MOV DH,cmsb_		; get MSB & LSB
    MOV BYTE ES:[BX+1],DL
    MOV BYTE ES:[BX+2],DH	; store MSB & LSB
    POP DX			; restore DX
    RET				; all done

_eoi:				; send EOI to PIC
    PUSH AX             	; we'll be using this
    MOV AL,020H         	; EOI
    OUT 020H,AL         	; EOI
    POP AX              	; restore AX
    RET                 	; all done

_iret1:				; execute EOI and then return
    CALL _eoi

finished:               	; Rx overrun error
    MOV BYTE stop_,0FFH 	; CRITICAL ERROR!!!
    JMP f2

_iret:                  	; all done routine
    MOV DX,0FFA2H       	; DART status reg
    IN AL,DX
    AND AL,1            	; RxD? (THIS WILL HAVE TO BE CHANGED TO CHECK
                        	;       FOR EXTERNAL STAT. ALSO)
    JNZ  sst            	; if so, than go to top of routine
f2:				; C equivalent:
				;     if(end > ptr)
				;	    goto okay;
				;     else
				;           stop=1;
;   MOV BX,ptr_
;   MOV DX,end_
;   CMP DX,BX
;   JG f3
;   MOV BYTE stop_,1	; Woaaaah!! Stop Everything!! - We're out of memory
f3:
    mov al,0b8h
    out 021h,al
    POP DS
    POP ES
    POP DX
    POP BX
    POP AX              	; retrieve registers
    call _eoi
    IRET                	; ALL DONE!!!!!!!
