; :ts=8
;%    .MODEL  MEMMOD,C
include asmglobal.h        
	LOCALS
	%MACS
	.LALL

	extrn   Stktop,Spsave,Sssave,piint:proc,doret:proc,eoi:proc

DMAEN   equ     4

	.DATA

	public  acc_delay
acc_delay       dw      0
diff            dw      0
tick1           dw      0
tick2           dw      0


	.CODE
dbase   dw      @Data           ; save loc for ds (must be in code segment)

;  This routine calculates the constant to be used in the delay loops
;  which satisfy the SCC's access recovery time.  This needs to be timed and
;  calculated because a fixed value would not work in a 4.77mhz XT
;  to a 40mhz 486 (and beyond).
	public set_acc_delay
set_acc_delay proc
	pushf
	cli
	push    ax
	push    bx
	push    cx
	push    dx

	mov     cx,1000

	mov     al,0                    ;latch counter zero.
	out     43h,al
	in      al,40h                  ;read counter zero.
	mov     ah,al
	in      al,40h
	xchg    ah,al
	mov     tick1,ax

h1:     loop    h1

	mov     al,0                    ;latch counter zero.
	out     43h,al
	in      al,40h                  ;read counter zero.
	mov     ah,al
	in      al,40h
	xchg    ah,al
	mov     tick2,ax
	mov     ax,tick1
	sub     ax,tick2
	mov     diff,ax ; Elapsed counts
	mov     bx,ax
	mov     dx,0
	mov     ax,5000 ; Divide by
	div     bx      ; the number of counts elapsed
	cmp     al,0
	jne     set_acc_2
	mov     al,1    ; Delay constant must be at least 1
set_acc_2:
	xor     ah,ah
	mov     acc_delay,ax

	pop     dx
	pop     cx
	pop     bx
	pop     ax
	popf
	ret
set_acc_delay   endp

	public  wrtscc
wrtscc  proc
	arg     cbase:word,ctl:word,reg:word,val:word

	pushf
	cli

	mov dx,cbase    ; get address of dma enable port
	add dx,DMAEN
	mov al,0        ; Write a 0 to disable DMA while we touch the scc
	out dx,al

	mov cx,acc_delay
Loop1:  nop
	loop Loop1

	mov dx,ctl      ; Get address of scc control reg
	mov ax,reg      ; Select register
	out dx,al

	mov cx,acc_delay
Loop2:  nop
	loop Loop2

	mov ax,val      ; Output value
	out dx,al

	mov cx,acc_delay
Loop3:  nop
	loop Loop3

	mov dx,cbase    ; get address of dma enable port
	add dx,DMAEN
	mov al,1        ; Enable DMA
	out dx,al

	popf
	ret
wrtscc  endp

	public  rdscc
rdscc   proc
	arg     cbase:word,ctl:word,reg:byte
	pushf
	cli

	mov dx,cbase    ; Get address of dma enable port
	add dx,DMAEN;
	mov al,0        ; Disable DMA while we touch the scc
	out dx,al;

	mov cx,acc_delay
Loop4:  nop
	loop Loop4

	mov dx,ctl      ; Get address of SCC control reg
	mov al,reg      ; Select register
	out dx,al;

	mov cx,acc_delay
Loop5:  nop
	loop Loop5

	in al,dx        ; read register
	xor ah,ah
	push ax         ; save return value

	mov cx,acc_delay
Loop6:  nop
	loop Loop6

	mov dx,cbase    ; get address of dma enable port
	add dx,DMAEN
	mov al,1        ; Enable DMA
	out dx,al

	pop     ax      ; recover return value
	popf
	ret
rdscc   endp

; pi0vec - Pi card #0 interrupt handler
	public  pi0vec
	label   pi0vec far
	push    ds              ; save on user stack
	mov     ds,cs:dbase     ; establish interrupt data segment

	mov     Sssave,ss       ; stash user stack context
	mov     Spsave,sp

	mov     ss,cs:dbase
	lea     sp,Stktop

    ; push    ax              ; save user regs on interrupt stack
    ; push    bx
    ; push    cx
    ; push    dx
    ; push    bp
    ; push    si
    ; push    di
    PUSHALL
    push    es
	call    eoi

	mov     ax,0            ; arg for service routine
	push    ax
	call    piint
	pop     ax
	jmp     doret

; pi1vec - Pi card #1 interrupt handler
	public  pi1vec
	label   pi1vec far
	push    ds              ; save on user stack
	mov     ds,cs:dbase     ; establish interrupt data segment

	mov     Sssave,ss       ; stash user stack context
	mov     Spsave,sp

	mov     ss,cs:dbase
	lea     sp,Stktop

    ; push    ax              ; save user regs on interrupt stack
    ; push    bx
    ; push    cx
    ; push    dx
    ; push    bp
    ; push    si
    ; push    di
    PUSHALL
	push    es
	call    eoi

	mov     ax,1            ; arg for service routine
	push    ax
	call    piint
	pop     ax
	jmp     doret

; pi2vec - Pi card #2 interrupt handler
	public  pi2vec
	label   pi2vec far
	push    ds              ; save on user stack
	mov     ds,cs:dbase     ; establish interrupt data segment

	mov     Sssave,ss       ; stash user stack context
	mov     Spsave,sp

	mov     ss,cs:dbase
	lea     sp,Stktop

    ; push    ax              ; save user regs on interrupt stack
    ; push    bx
    ; push    cx
    ; push    dx
    ; push    bp
    ; push    si
    ; push    di
    PUSHALL
    push    es
	call    eoi

	mov     ax,2            ; arg for service routine
	push    ax
	call    piint
	pop     ax
	jmp     doret

	end
