home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume6 / glib / part06 / pc-ints.asm < prev    next >
Encoding:
Assembly Source File  |  1989-05-14  |  12.2 KB  |  440 lines

  1. @ab    equ 6        ;use big model
  2. ; $Id: pc-ints.asm,v 1.6 89/05/06 17:13:38 lee Exp $
  3. ;
  4. ; the following constants are hardware specific to the MPU401 & OP4000
  5. ; MIDI interface controllers
  6. ; $Log:    pc-ints.asm,v $
  7. ; Revision 1.6  89/05/06  17:13:38  lee
  8. ; rel. to comp.sources.misc
  9. ;
  10. BASE_ADDRESS_MPU     equ 330h
  11. STATUS_PORT_MPU     equ BASE_ADDRESS_MPU  + 1
  12. COMMAND_PORT_MPU     equ BASE_ADDRESS_MPU  + 1
  13. DATA_PORT_MPU         equ BASE_ADDRESS_MPU  + 0
  14. Tx_EMT             equ 40h    ;midi transmitter ready for more data
  15. Rx_NEMT            equ 80h    ;midi receiver has data ready
  16. MPU_INT            equ 2
  17. MPU_INT_MASK        equ 4
  18. ;
  19. ; the remaining constants are for the AT&T PC6300 and compatible PC's
  20. ;
  21. TIMER_INT        equ 0
  22. TIMER_INT_MASK        equ 1
  23. HW_INT_MASK        equ MPU_INT_MASK OR TIMER_INT_MASK
  24. INT_CTLR_PORT        equ 20h    ;port to send EOI command to
  25. INT_CTLR_IMR         equ 21h    ;port to mask interrupts
  26. EOI_CODE        equ 20h    ;EOI command
  27. T_55MS       equ    0000h        ; 8253 value for 55 ms
  28. T_5MS       equ    174dh        ; 8253 value for 5 ms
  29. TIC_55MS   equ    11        ; Number of timer tics to equal 55 ms
  30. PIT_MODE   equ    36h    ; 8253 mode: 00 11 011 0 -> cntr0,LSB/MSB,mode 3,binary
  31. PIT_CNT0   equ    40h        ; Counter 0 port for 8253 PIT
  32. PIT_CTRL   equ    43h        ; Control port for 8253 PIT
  33. USER_TMR   equ    1ch        ; User Timer (55 ms) Int. Vector
  34. ;
  35.  
  36. ;********************
  37. ;**   macros       **
  38. ;********************
  39. ;
  40. c_in    macro            ;this macro sets up a stack frame
  41.     push    bp        ;must save bp reg for 'c' progs
  42.     mov    bp, sp            ;set up frame pointer
  43.     push di
  44.     push si            ;save register vars
  45.     endm
  46. ;
  47. c_out    macro            ;This macro cleans up for return to 'C'
  48.     pop si
  49.     pop di
  50.     mov sp, bp
  51.     pop    bp            ;restore caller's frame pointer
  52.     cld                ;clear direction flag 
  53.     ret                ;and return
  54.     endm
  55. ;
  56. push_all_regs    macro
  57.     push    es
  58.     push    ds
  59.     push    dx
  60.     push    cx
  61.     push    bx
  62.     push    si
  63.     push    di
  64.     push    ax
  65.     push    bp
  66.     endm
  67. ;
  68. pop_all_regs    macro
  69.     pop    bp
  70.     pop    ax
  71.     pop    di
  72.     pop    si
  73.     pop    bx
  74.     pop    cx
  75.     pop    dx
  76.     pop    ds
  77.     pop    es
  78.     endm
  79. ;
  80. enable_IMR    macro num        ;this macro clears (enables)
  81.                     ;interrupts in the interrupt mask reg
  82.     in        al, INT_CTLR_IMR    ;read in current int mask
  83.     and        al, 0ffh - num        ;clear the requested IMR bit
  84.     out        INT_CTLR_IMR, al    ;and write it back out
  85.     endm
  86. ;
  87. disable_IMR    macro num        ;disable interrupts in the IMR
  88.     in        al, INT_CTLR_IMR    ;read in current int mask
  89.     or        al, num            ;set the requested IMR bit
  90.     out        INT_CTLR_IMR, al    ;and write it out
  91.     endm
  92. ;
  93. ack_int    macro                ;this macro sends non-specific EOI
  94.                         ;to the int controller chip in the PC
  95.     mov al, EOI_CODE
  96.     out INT_CTLR_PORT, al
  97.     sti
  98.     endm
  99. ;
  100.  
  101. ;************************************************************
  102. ;**                                                        **
  103. ;** DATA GROUP DECLARATION                                 **
  104. ;**                                                        **
  105. ;************************************************************
  106. ;
  107.     
  108. dgroup    group    data
  109. data    segment    word public 'data'
  110.     assume    ds:dgroup
  111. ;
  112. ; --- The following vars are used to manage a very small stack
  113. ;     that is used for interrupt enable/disable stacking
  114. ;
  115. INT_STACK_SIZE        equ    8 * 1
  116. int_stack        db    (INT_STACK_SIZE/8) dup ('intstack')
  117. int_stack_pointer     dw    0
  118. ;
  119. ; --- The following provide a circular character buffer used to
  120. ;     store data received from the MIDI interface
  121. ;
  122. BUFFER_SIZE        equ    512
  123. _wrt_index        dw    0
  124. _rd_index        dw    0
  125. _midi_buffer        db    BUFFER_SIZE dup (0)
  126. public _wrt_index
  127. public _rd_index
  128. public _midi_buffer
  129. ;
  130. ; --- The following vars are used to keep a running tally of the
  131. ;     programmable timer ticks.
  132. ;
  133. _hzcount        dd    0
  134. int_cnt            dw     0
  135. public    _hzcount
  136. ;
  137. data    ends
  138. ;
  139.  
  140. ;************************************************************
  141. ;**                                                        **
  142. ;** CODE SEGMENT                                           **
  143. ;**                                                        **
  144. ;**                                                        **
  145. ;************************************************************
  146. ;
  147. ;
  148.     extrn _fatal_dos_handler:far    ;'C' routine to handle DOS errors
  149.     extrn _bye:far            ; exit routine for Ctl-brk
  150.  
  151. _code segment byte public 'code'
  152.     assume cs:_code
  153.     public     _ctl_brk
  154.     public     _asm_fatal_dos_handler
  155.     public     _disable_ints
  156.     public     _enable_ints
  157.     public     _init_enable_MPU
  158.     public     _init_enable_TIMER
  159.     public     _reset_TIMER
  160.     public     _write_data_MPU
  161.     public     _read_MPU
  162.     public     _midi_isr
  163.     public     _tick_isr
  164.  
  165. ;
  166. ;************************************************************
  167. ;**                                                        **
  168. ;** INTERRUPT HANDLERS                                     **
  169. ;**                                                        **
  170. ;**                                                        **
  171. ;************************************************************
  172. _ctl_brk    proc    far
  173. ;
  174. ;    Control-Break Interrupt Service Routine
  175. ;
  176. ctl_st: cli            ; make sure no interrupts
  177.     mov    ax,ds
  178.     mov    ss,ax        ; ss = ds :: so chkstk() doesn't fail in quit()
  179.     mov    sp,0fffeh    ;  and sp = hi mem
  180.     mov    ax,1        ; exit code
  181.     sti            ; turn interrupts back on
  182.     push    ax
  183.     call    _bye
  184.     pop    bp        ; not needed, never returns here
  185.     iret            ;  or here
  186. _ctl_brk    endp
  187. ;
  188. ;    Fatal Dos Error Interrupt Service Routine
  189. ;
  190. _asm_fatal_dos_handler proc far
  191.     push_all_regs        ;save machine state
  192.     push    di
  193.     push    ax        ;push args for function
  194.     mov    ax, dgroup
  195.     mov    ds, ax        ;address data segment
  196.     mov    es, ax        ;and extra segmant
  197.     call    _fatal_dos_handler ;handler(ax, di)
  198.     pop    ax
  199.     pop    ax
  200.     pop_all_regs
  201.     mov    al,0        ;tell DOS to ignore error
  202.     iret
  203. _asm_fatal_dos_handler endp
  204. ;
  205. ;
  206. ;************************************************************
  207. ;** MIDI_ISR                                               **
  208. ;** This is the MPU int service routine                    **
  209. ;** It reads data from MPU data port until there is no more** 
  210. ;** and stores in a circular buffer               **
  211. ;************************************************************
  212. ;
  213. _midi_isr    proc    far
  214.     push_all_regs                ;save machine state
  215.     mov    ax, dgroup
  216.     mov    ds, ax
  217.     disable_IMR MPU_INT_MASK
  218.     sti
  219. do_another:
  220.     mov    dx, DATA_PORT_MPU
  221.     in    al, dx        ;read in the interrupt data from MPU
  222.  
  223.         inc    _wrt_index            ;bump up write pointer
  224.         cmp    _wrt_index, 01ffh        ;is index at top of buff?
  225.         jle    wrt_index_ok
  226.         mov    _wrt_index, 0            ;if yes, wraparound to bottom
  227. wrt_index_ok:                    ;of buffer 
  228.         mov    bx, _wrt_index
  229.         mov    _midi_buffer[bx], al        ;move data into buffer
  230.  
  231.         mov dx, STATUS_PORT_MPU            ;DX = &status port
  232.         in    al, dx                ;read status port
  233.         and al, Rx_NEMT                ;is there data to read?
  234.     jz    do_another            ;go back if so
  235. ;isr return
  236.     cli                    ;turn off system ints
  237.     enable_IMR MPU_INT_MASK
  238.     ack_int                    ;and acknowlege interrupt
  239.     pop_all_regs                ;restore machine state
  240.     iret                    ;and leave
  241. _midi_isr    endp
  242. ;
  243. ;********************************************************************
  244. ;*    TICK_ISR
  245. ;*    The interrupt service routine for the programmable timer.
  246. ;*    Timer is currently set at 5 ms. intervals.
  247. ;********************************************************************
  248. ;
  249. _tick_isr     proc far
  250. ;
  251. tmr_st:    push    ds
  252.     push    ax
  253.     mov    ax, dgroup
  254.     mov    ds, ax        ;must have our data segment
  255.     disable_IMR TIMER_INT_MASK
  256.     sti
  257.     add    word ptr _hzcount, 1
  258.     adc    word ptr _hzcount + 2, 0
  259.     inc    int_cnt
  260.     cmp    int_cnt,TIC_55MS
  261.     jge    tm1
  262.     cli
  263.     enable_IMR TIMER_INT_MASK
  264.     ack_int
  265.     pop    ax
  266.     pop    ds
  267.     iret
  268.  
  269. tm1:    mov    int_cnt,0
  270.     int    USER_TMR
  271.     cli
  272.     enable_IMR TIMER_INT_MASK
  273.     ack_int
  274.     pop    ax
  275.     pop    ds
  276.     iret
  277. _tick_isr endp
  278.  
  279.  
  280. ;
  281. ;************************************************************
  282. ;** DISABLE_INTS()                                         **
  283. ;** Called to disable interrupts.  stacks old int          **
  284. ;** status before disabling, so that nesting is            **
  285. ;** preserved.                                             **
  286. ;************************************************************
  287. ;
  288. _disable_ints proc far
  289.     cli
  290.         in    al, INT_CTLR_IMR    ;read in current int mask
  291.     mov    dl, al            ;move it to dl
  292.     and    dl, HW_INT_MASK        ;extract the bit for MPU ints
  293.     mov    bx, int_stack_pointer    ;get current stack pointer
  294.     mov    int_stack[bx], dl    ;store out int status there
  295.     inc    bx
  296.     mov    int_stack_pointer, bx    ;write back new stack pointer value
  297.     or    al, HW_INT_MASK        ;mask off int
  298.         out    INT_CTLR_IMR, al    ;and write it out
  299.     sti
  300.     ret
  301. _disable_ints endp
  302. ;
  303. ;************************************************************
  304. ;** ENABLE_INTS()                                          **
  305. ;** Restores whatever the int status was before            **
  306. ;** DISABLE_INTS() was called.                             **
  307. ;** Note that calls to enable and disable must be matched  **
  308. ;** or chaos will occur                                    **
  309. ;************************************************************
  310. ;
  311. _enable_ints proc far
  312.     cli
  313.         in    al, INT_CTLR_IMR    ;read in current int mask
  314.     and    al, 0ffh - HW_INT_MASK     ; get all the bits except the ones
  315.                     ; for out ints
  316.     mov    bx, int_stack_pointer    ;get int stack pointer
  317.     dec    bx            ;move it down
  318.     mov    int_stack_pointer, bx    ;store it
  319.     or    al, int_stack[bx]    ;or in int status with old one
  320.         out    INT_CTLR_IMR, al    ;and write it out
  321.     sti                ;turn ints on now
  322.     ret
  323. _enable_ints endp
  324. ;
  325. ;************************************************************
  326. ;** INIT_ENABLE_MPU()                                  **
  327. ;** Starts up the MPU ints.                               **
  328. ;**                                                        **
  329. ;************************************************************
  330. ;
  331. _init_enable_MPU proc far
  332.     cli
  333.     enable_IMR MPU_INT_MASK
  334.     sti
  335.     ret
  336. _init_enable_MPU endp
  337. ;;
  338. ;************************************************************
  339. ;** INIT_ENABLE_TIMER()                                  **
  340. ;** Starts up the TIMER ints.                               **
  341. ;**                                                        **
  342. ;************************************************************
  343. ;
  344. _init_enable_TIMER proc far
  345.     cli
  346. ; Set 8253 PIT for different timing
  347. ;
  348.     mov    al,PIT_MODE
  349.     out    PIT_CTRL,al    ; Set 8253 mode
  350.     mov    ax,T_5MS
  351.     out    PIT_CNT0,al
  352.     mov    al,ah
  353.     out    PIT_CNT0,al    ; Set new timing
  354.     enable_IMR TIMER_INT_MASK
  355.     sti
  356.     ret
  357. _init_enable_TIMER endp 
  358. ;
  359. ;
  360. ;************************************************************
  361. ;** RESET_TIMER()                                          **
  362. ;** Sets timer values back to what they were               **
  363. ;**                                                        **
  364. ;************************************************************
  365. _reset_TIMER    proc far
  366.  
  367.     disable_IMR TIMER_INT_MASK
  368.     mov    al,PIT_MODE
  369.     out    PIT_CTRL,al    ; Set 8253 mode
  370.     mov    ax,T_55MS
  371.     out    PIT_CNT0,al
  372.     mov    al,ah
  373.     out    PIT_CNT0,al    ; Reset timing
  374.     enable_IMR TIMER_INT_MASK
  375.     ret
  376. _reset_TIMER    endp
  377. ;
  378.  
  379. ;************************************************************
  380. ;** WRITE_DATA_MPU(DATA)                                   **
  381. ;** sends a byte to the MPU data port                      **
  382. ;** waits for handshake                                    **
  383. ;**                                                        **
  384. ;************************************************************
  385. ;
  386. ;
  387. _write_data_MPU proc far
  388.     c_in
  389.     mov bx, @ab[bp]            ;get data byte in bl reg
  390.     call write_sub            ;and call fast sub
  391.     c_out                ;leave
  392. _write_data_MPU endp
  393. ;
  394. ;************************************************************
  395. ;**                                                        **
  396. ;**   write_sub                                            **
  397. ;**   Writes data to MPU. on entry, byte in bl            **
  398. ;**   ax, cx, cx destroyed                                 **
  399. ;************************************************************
  400. ;
  401. write_sub proc near
  402.     mov dx, STATUS_PORT_MPU    ;set up pointer to MPU port
  403. write_clear_loop:
  404.     in    al, dx
  405.     and al, Tx_EMT
  406.     jnz write_clear_loop
  407.     dec    dx            ;point to data reg
  408.     mov    al, bl
  409.     out    dx, al            ;send out the data
  410.     ret
  411. write_sub endp
  412. ;
  413. ;************************************************************
  414. ;** read_MPU()                                            **
  415. ;** reads a byte from the MPU    eata port                   **
  416. ;** waits for handshake                                    **
  417. ;**                                                        **
  418. ;************************************************************
  419. ;
  420. _read_MPU proc far
  421.     c_in
  422. read_clear_loop:
  423.     mov dx, STATUS_PORT_MPU    ;DX = &status port
  424.     in    al, dx
  425.     and al, Rx_NEMT
  426.     jnz read_clear_loop
  427.     dec    dx            ;point to data reg
  428.     in    al, dx
  429.     xor    ah, ah
  430.     c_out
  431. _read_MPU endp
  432.  
  433. ;
  434.  
  435. _code    ends
  436.     end
  437.  
  438.