comment %

support file for loading and installing "virgin" vector table
should just load file directly over vector table instead of into mem first.

this probably be modified to only load 512 bytes of vector table, since
some games load from int 80h upward.  No ISRs above 7F should be called anyway

%






reset_vectors proc


;; open the file and load in 1k chunks into base memory

        mov     dx, offset vect_file

        ;should be call open_file

        mov     ax, 3d00h
        int     21h              ; Openfile
        jc      vecFileerr
        mov     bp,ax            ; save handle in BP


        lea     dx,endflag       ; DS:DX=buffer "scratch" area
                
        mov     cx, 1024
        mov     bx, bp
        mov     ax, 3f00h
        int     21h
        jc      vecfileerr

        call    close_file


        push    es

        mov     di, 0
        mov     es, di
        mov     si, offset endflag

        add     si, 2*4         ; start with INT 2
 
        add     di, 2*4         ; 
        mov     cx, 252         ; 255-(20*4)
        cli
revect:
        mov     eax, dword ptr ds:[si]          ; why am I not using rep stosd?
        mov     dword ptr es:[di],eax
        add     di, 4
        add     si, 4
        loop    revect
        sti
                
        pop     es
        ret
vecfileerr:
        push    cs
        pop     ds
        mov     dx, offset vecFilemess
        mov     ah, 9
        int     21h

        mov     ax,4c01h
        int     21h

reset_vectors endp

vecFilemess     db      "Error: File not found:"
vect_file       db      "vectable.dat",0,CR,LF,"$"  ;vector datafile


changeISR proc near
;interrupts should be disabled.
;al=interrupt vector to change
;ES:BX=new vector
;ES:DX=storage location for old vector



        push    ecx
        push    bx
        push    ds
        push    ax                              ; save original vector#


        push    0
        pop     ds

        xor     ah, ah
        shl     ax, 2                           ; multiply vector x 4

        xchg    ax, bx

        push    si
        mov     si, dx


        cli

       

        mov     ecx, dword ptr ds:[bx]          ; get real vector

        mov     dword ptr es:[si], ecx            ; save it.

        pop     si

        mov     word ptr ds:[bx], ax            ; set new vector to flopper
        mov     word ptr ds:[bx+2], es

        pop     ax
    ;    test    al, BIT7
    ;    jnz     skip_revector                   ; if already above 80h, ignore

    ;    or      al, BIT7
                
    ;    xor     ah, ah
    ;    shl     ax, 2                           ; multiply vector x 4

    ;    xchg    ax, bx
    ;    mov     dword ptr ds:[bx], edx

skip_revector:
        sti
        pop     ds
        pop     bx
        pop     ecx
        ret
changeISR endp



; relocate IRQ's 0-7 to 50-57.
; This should allow us to still be in control of keyboard even for games that
; revector INT 9 and never call the BIOS.
; code stolen from undocumented PC.

RelocateIrqs proc


        cli                        ; disable interrupts
                                   ; Program int controller 1
                                   ; ------------------------
        in      al, 21h            ; get current interrupt mask
        mov     ah, al             ; save for later
        call    IODELAY
        mov     al, 11h            ; Init command 1, cascade & 
        out     20h, al            ;   require 4th init byte
        call    IODELAY
        mov     al, 50h            ; Init command 2
        out     21h, al            ;   switch IRQ's to int 50h
        call    IODELAY
        mov     al, 4              ; Init command 3
        out     21h, al            ;   slave controller on IRQ 2
        call    IODELAY
        mov     al, 1              ; Init command 4, normal EOI
        out     21h, al            ;   non-buffered, 80x86
        call    IODELAY
        mov     al, ah             ; Operation command 1
        out     21h, al            ;   restore interrupt mask

                                   ; Now copy interrupt vectors
                                   ; --------------------------
        xor     ax, ax
        mov     es, ax             ; set segment registers to 
        mov     ds, ax             ;   point to interrupt table
        mov     cx, 8 * 2          ; number of words to transfer
        mov     si, 8 * 4          ; start at interrupt 8
        mov     di, 50h * 4        ; xfer to interrupt 50-57h
        cld
        rep     movsw              ; transfer interrupt vectors
        sti                        ; enable interrupts
        ret

relocateIrqs endp





;this doesn't really belong in the vector table support file...

copy_code       proc    near


        push    cs
        pop     ds


        ; copy our code to just above 512k

        mov     di, offset flopper_top
        mov     cx, offset flopper_bottom
        sub     cx, di

        push    cx
        mov     di, FLOPPER_START
        shr     cx, 4                           ; make into segments
        inc     cx                              ; add 1 to be safe.
        add     di, cx
        pop     cx

        push    di
        pop     es
        xor     di, di

        mov     si, offset flopper_top
        rep     movsb
        ret
copy_code       endp




;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;    I/O DELAY
;       Delay to ensure successive I/O operations to the same 
;       device are not too fast on a fast CPU.  First time 
;       iodelay is called, a 5 mS delay occurs to calibrate
;       the delay loop.
;
;       Called with:    nothing
;
;       Returns:        delay of 1 to 16 uS
;
;       Regs used:      none (flags altered)

iodelay proc    near
        push    cx
        mov     cx, cs:[io_count]
        jcxz    io_init
io_delay_loop:
        loop    io_delay_loop      ; 13 cycles per loop on a 386
        pop     cx
        ret

; first time run, so determine initialization value and save

io_init:
        push    ax
        push    bx
        push    dx
        push    es

        mov     ax, cs
        mov     es, ax
        mov     ax, 8300h          ; set wait interval
        mov     cx, 0
        mov     dx, 5000           ; delay 5 mS, util wait flag
        mov     bx, offset io_flag ;  is set
        int     15h                ; start 5 mS delay
        jc      io_failed_15       ; unimplemented or in progress

; the RTC timer has begun, and will set bit 7 of the wait flag when
; 5 mS elapses.  Meanwhile, the software loop counts down slowly for
; slow systems, and fast for fast systems.  The loop is 30 cycles 
; on a 386 CPU.  Other CPUs will vary slightly from this.

        dec     cx                 ; cx = FFFFh

io_delay_loop2:
        test    cs:[io_flag], 80h  ; flag set after 5 mS
        jnz     io_5ms_done        ; jump if 5 ms complete
        jmp     short $+2
        loop    io_delay_loop2

        mov     ax, 100            ; gets here if > 400 Mhz CPU,
        jmp     io_exit            ;  so use really large number

; cx = countdown from FFFF 

io_5ms_done:
        mov     ax, 0FFFFh
        sub     ax, cx             ; get number of times looped
        mov     bx, 1500           ; adjustment factor
        xor     dx, dx             ; dx zeroed for divde
        div     bx                 ; ax= dx:ax/cx
        cmp     ax, 0
        je      io_1_delay         ; set at least 1 delay
        jmp     io_set             ; ax = delay value

io_failed_15:
        or      ah, ah             ; was int 15 supported or busy?
        jz      io_exit            ; jump if busy, try again later
                                   ; only slow machines fail int 15h
io_1_delay:
        mov     ax, 1              ; mininum delay period
io_set:
        mov     cs:[io_count], ax  ; load delay value
io_exit:
        pop     es
        pop     dx
        pop     bx
        pop     ax
        pop     cx
        ret
iodelay endp

io_count dw     0                  ; 0 = non-intialized count
io_flag  db     0                  ; bit 7=1 at end of 5mS wait

; ÄÄÄÄÄÄÄÄÄÄÄÄÄ end of iodelay subroutine ÄÄÄÄÄÄÄÄÄÄÄÄÄÄ


