home *** CD-ROM | disk | FTP | other *** search
- @ab equ 6 ;use big model
- ; $Id: pc-ints.asm,v 1.6 89/05/06 17:13:38 lee Exp $
- ;
- ; the following constants are hardware specific to the MPU401 & OP4000
- ; MIDI interface controllers
- ; $Log: pc-ints.asm,v $
- ; Revision 1.6 89/05/06 17:13:38 lee
- ; rel. to comp.sources.misc
- ;
- ;
- ;
- BASE_ADDRESS_MPU equ 330h
- STATUS_PORT_MPU equ BASE_ADDRESS_MPU + 1
- COMMAND_PORT_MPU equ BASE_ADDRESS_MPU + 1
- DATA_PORT_MPU equ BASE_ADDRESS_MPU + 0
- Tx_EMT equ 40h ;midi transmitter ready for more data
- Rx_NEMT equ 80h ;midi receiver has data ready
- MPU_INT equ 2
- MPU_INT_MASK equ 4
- ;
- ; the remaining constants are for the AT&T PC6300 and compatible PC's
- ;
- TIMER_INT equ 0
- TIMER_INT_MASK equ 1
- HW_INT_MASK equ MPU_INT_MASK OR TIMER_INT_MASK
- INT_CTLR_PORT equ 20h ;port to send EOI command to
- INT_CTLR_IMR equ 21h ;port to mask interrupts
- EOI_CODE equ 20h ;EOI command
- T_55MS equ 0000h ; 8253 value for 55 ms
- T_5MS equ 174dh ; 8253 value for 5 ms
- TIC_55MS equ 11 ; Number of timer tics to equal 55 ms
- PIT_MODE equ 36h ; 8253 mode: 00 11 011 0 -> cntr0,LSB/MSB,mode 3,binary
- PIT_CNT0 equ 40h ; Counter 0 port for 8253 PIT
- PIT_CTRL equ 43h ; Control port for 8253 PIT
- USER_TMR equ 1ch ; User Timer (55 ms) Int. Vector
- ;
-
- ;********************
- ;** macros **
- ;********************
- ;
- c_in macro ;this macro sets up a stack frame
- push bp ;must save bp reg for 'c' progs
- mov bp, sp ;set up frame pointer
- push di
- push si ;save register vars
- endm
- ;
- c_out macro ;This macro cleans up for return to 'C'
- pop si
- pop di
- mov sp, bp
- pop bp ;restore caller's frame pointer
- cld ;clear direction flag
- ret ;and return
- endm
- ;
- push_all_regs macro
- push es
- push ds
- push dx
- push cx
- push bx
- push si
- push di
- push ax
- push bp
- endm
- ;
- pop_all_regs macro
- pop bp
- pop ax
- pop di
- pop si
- pop bx
- pop cx
- pop dx
- pop ds
- pop es
- endm
- ;
- enable_IMR macro num ;this macro clears (enables)
- ;interrupts in the interrupt mask reg
- in al, INT_CTLR_IMR ;read in current int mask
- and al, 0ffh - num ;clear the requested IMR bit
- out INT_CTLR_IMR, al ;and write it back out
- endm
- ;
- disable_IMR macro num ;disable interrupts in the IMR
- in al, INT_CTLR_IMR ;read in current int mask
- or al, num ;set the requested IMR bit
- out INT_CTLR_IMR, al ;and write it out
- endm
- ;
- ack_int macro ;this macro sends non-specific EOI
- ;to the int controller chip in the PC
- mov al, EOI_CODE
- out INT_CTLR_PORT, al
- sti
- endm
- ;
-
- ;************************************************************
- ;** **
- ;** DATA GROUP DECLARATION **
- ;** **
- ;************************************************************
- ;
-
- dgroup group data
- data segment word public 'data'
- assume ds:dgroup
- ;
- ; --- The following vars are used to manage a very small stack
- ; that is used for interrupt enable/disable stacking
- ;
- INT_STACK_SIZE equ 8 * 1
- int_stack db (INT_STACK_SIZE/8) dup ('intstack')
- int_stack_pointer dw 0
- ;
- ; --- The following provide a circular character buffer used to
- ; store data received from the MIDI interface
- ;
- BUFFER_SIZE equ 512
- _wrt_index dw 0
- _rd_index dw 0
- _midi_buffer db BUFFER_SIZE dup (0)
- public _wrt_index
- public _rd_index
- public _midi_buffer
- ;
- ; --- The following vars are used to keep a running tally of the
- ; programmable timer ticks.
- ;
- _hzcount dd 0
- int_cnt dw 0
- public _hzcount
- ;
- data ends
- ;
-
- ;************************************************************
- ;** **
- ;** CODE SEGMENT **
- ;** **
- ;** **
- ;************************************************************
- ;
- ;
- extrn _fatal_dos_handler:far ;'C' routine to handle DOS errors
- extrn _bye:far ; exit routine for Ctl-brk
-
- _code segment byte public 'code'
- assume cs:_code
- public _ctl_brk
- public _asm_fatal_dos_handler
- public _disable_ints
- public _enable_ints
- public _init_enable_MPU
- public _init_enable_TIMER
- public _reset_TIMER
- public _write_data_MPU
- public _read_MPU
- public _midi_isr
- public _tick_isr
-
- ;
- ;************************************************************
- ;** **
- ;** INTERRUPT HANDLERS **
- ;** **
- ;** **
- ;************************************************************
- _ctl_brk proc far
- ;
- ; Control-Break Interrupt Service Routine
- ;
- ctl_st: cli ; make sure no interrupts
- mov ax,ds
- mov ss,ax ; ss = ds :: so chkstk() doesn't fail in quit()
- mov sp,0fffeh ; and sp = hi mem
- mov ax,1 ; exit code
- sti ; turn interrupts back on
- push ax
- call _bye
- pop bp ; not needed, never returns here
- iret ; or here
- _ctl_brk endp
- ;
- ; Fatal Dos Error Interrupt Service Routine
- ;
- _asm_fatal_dos_handler proc far
- push_all_regs ;save machine state
- push di
- push ax ;push args for function
- mov ax, dgroup
- mov ds, ax ;address data segment
- mov es, ax ;and extra segmant
- call _fatal_dos_handler ;handler(ax, di)
- pop ax
- pop ax
- pop_all_regs
- mov al,0 ;tell DOS to ignore error
- iret
- _asm_fatal_dos_handler endp
- ;
- ;
- ;************************************************************
- ;** MIDI_ISR **
- ;** This is the MPU int service routine **
- ;** It reads data from MPU data port until there is no more**
- ;** and stores in a circular buffer **
- ;************************************************************
- ;
- _midi_isr proc far
- push_all_regs ;save machine state
- mov ax, dgroup
- mov ds, ax
- disable_IMR MPU_INT_MASK
- sti
- do_another:
- mov dx, DATA_PORT_MPU
- in al, dx ;read in the interrupt data from MPU
-
- inc _wrt_index ;bump up write pointer
- cmp _wrt_index, 01ffh ;is index at top of buff?
- jle wrt_index_ok
- mov _wrt_index, 0 ;if yes, wraparound to bottom
- wrt_index_ok: ;of buffer
- mov bx, _wrt_index
- mov _midi_buffer[bx], al ;move data into buffer
-
- mov dx, STATUS_PORT_MPU ;DX = &status port
- in al, dx ;read status port
- and al, Rx_NEMT ;is there data to read?
- jz do_another ;go back if so
- ;isr return
- cli ;turn off system ints
- enable_IMR MPU_INT_MASK
- ack_int ;and acknowlege interrupt
- pop_all_regs ;restore machine state
- iret ;and leave
- _midi_isr endp
- ;
- ;********************************************************************
- ;* TICK_ISR
- ;* The interrupt service routine for the programmable timer.
- ;* Timer is currently set at 5 ms. intervals.
- ;********************************************************************
- ;
- _tick_isr proc far
- ;
- tmr_st: push ds
- push ax
- mov ax, dgroup
- mov ds, ax ;must have our data segment
- disable_IMR TIMER_INT_MASK
- sti
- add word ptr _hzcount, 1
- adc word ptr _hzcount + 2, 0
- inc int_cnt
- cmp int_cnt,TIC_55MS
- jge tm1
- cli
- enable_IMR TIMER_INT_MASK
- ack_int
- pop ax
- pop ds
- iret
-
- tm1: mov int_cnt,0
- int USER_TMR
- cli
- enable_IMR TIMER_INT_MASK
- ack_int
- pop ax
- pop ds
- iret
- _tick_isr endp
-
-
- ;
- ;************************************************************
- ;** DISABLE_INTS() **
- ;** Called to disable interrupts. stacks old int **
- ;** status before disabling, so that nesting is **
- ;** preserved. **
- ;************************************************************
- ;
- _disable_ints proc far
- cli
- in al, INT_CTLR_IMR ;read in current int mask
- mov dl, al ;move it to dl
- and dl, HW_INT_MASK ;extract the bit for MPU ints
- mov bx, int_stack_pointer ;get current stack pointer
- mov int_stack[bx], dl ;store out int status there
- inc bx
- mov int_stack_pointer, bx ;write back new stack pointer value
- or al, HW_INT_MASK ;mask off int
- out INT_CTLR_IMR, al ;and write it out
- sti
- ret
- _disable_ints endp
- ;
- ;************************************************************
- ;** ENABLE_INTS() **
- ;** Restores whatever the int status was before **
- ;** DISABLE_INTS() was called. **
- ;** Note that calls to enable and disable must be matched **
- ;** or chaos will occur **
- ;************************************************************
- ;
- _enable_ints proc far
- cli
- in al, INT_CTLR_IMR ;read in current int mask
- and al, 0ffh - HW_INT_MASK ; get all the bits except the ones
- ; for out ints
- mov bx, int_stack_pointer ;get int stack pointer
- dec bx ;move it down
- mov int_stack_pointer, bx ;store it
- or al, int_stack[bx] ;or in int status with old one
- out INT_CTLR_IMR, al ;and write it out
- sti ;turn ints on now
- ret
- _enable_ints endp
- ;
- ;************************************************************
- ;** INIT_ENABLE_MPU() **
- ;** Starts up the MPU ints. **
- ;** **
- ;************************************************************
- ;
- _init_enable_MPU proc far
- cli
- enable_IMR MPU_INT_MASK
- sti
- ret
- _init_enable_MPU endp
- ;;
- ;************************************************************
- ;** INIT_ENABLE_TIMER() **
- ;** Starts up the TIMER ints. **
- ;** **
- ;************************************************************
- ;
- _init_enable_TIMER proc far
- cli
- ; Set 8253 PIT for different timing
- ;
- mov al,PIT_MODE
- out PIT_CTRL,al ; Set 8253 mode
- mov ax,T_5MS
- out PIT_CNT0,al
- mov al,ah
- out PIT_CNT0,al ; Set new timing
- enable_IMR TIMER_INT_MASK
- sti
- ret
- _init_enable_TIMER endp
- ;
- ;
- ;************************************************************
- ;** RESET_TIMER() **
- ;** Sets timer values back to what they were **
- ;** **
- ;************************************************************
- _reset_TIMER proc far
-
- disable_IMR TIMER_INT_MASK
- mov al,PIT_MODE
- out PIT_CTRL,al ; Set 8253 mode
- mov ax,T_55MS
- out PIT_CNT0,al
- mov al,ah
- out PIT_CNT0,al ; Reset timing
- enable_IMR TIMER_INT_MASK
- ret
- _reset_TIMER endp
- ;
-
- ;************************************************************
- ;** WRITE_DATA_MPU(DATA) **
- ;** sends a byte to the MPU data port **
- ;** waits for handshake **
- ;** **
- ;************************************************************
- ;
- ;
- _write_data_MPU proc far
- c_in
- mov bx, @ab[bp] ;get data byte in bl reg
- call write_sub ;and call fast sub
- c_out ;leave
- _write_data_MPU endp
- ;
- ;************************************************************
- ;** **
- ;** write_sub **
- ;** Writes data to MPU. on entry, byte in bl **
- ;** ax, cx, cx destroyed **
- ;************************************************************
- ;
- write_sub proc near
- mov dx, STATUS_PORT_MPU ;set up pointer to MPU port
- write_clear_loop:
- in al, dx
- and al, Tx_EMT
- jnz write_clear_loop
- dec dx ;point to data reg
- mov al, bl
- out dx, al ;send out the data
- ret
- write_sub endp
- ;
- ;************************************************************
- ;** read_MPU() **
- ;** reads a byte from the MPU eata port **
- ;** waits for handshake **
- ;** **
- ;************************************************************
- ;
- _read_MPU proc far
- c_in
- read_clear_loop:
- mov dx, STATUS_PORT_MPU ;DX = &status port
- in al, dx
- and al, Rx_NEMT
- jnz read_clear_loop
- dec dx ;point to data reg
- in al, dx
- xor ah, ah
- c_out
- _read_MPU endp
-
- ;
-
- _code ends
- end
-
-