comment %
constants:
flopper_top and flopper_bottom labels are used to determine the total
amount of code to move above 512k
routines grow up from 512k toward 640
disk_start points to the 1st image's  size+params+image data
%











flopper_top:

; the following structure data will always be located on a paragraph
; boundry, so it can always be accessed at offset 0 of whatever CS we're
; running in.  This is important, so don't add any code between flopper_top
; and flopper_data struc

flopper_data struc
        flagbyte        db      DISK_PROTECTED  ; misc flags
        vidmode         db      ?               ; current video mode
        vidpage         db      ?               ; current video page
        cursorpos       dw      ?               ; current cusor position
flopper_data ends

flopperdata flopper_data <>

;様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様
;        O L D     I N T E R R U P T     V E C T O R S
;様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様
realInt13:
        db      0eah            ; far jmp into interrupt code
        dd      ?
realInt15:
        pushf
        db      09ah            ; far call into interrupt code
        dd      ?
        ret
realInt5:                       ; far jmp to interrupt code
        db      0eah
        dd      ?
;
;vidstorage      dd      ?       ; storage for video mode, page, cursor pos

;様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様
;        I N T E R R U P T        1 3 h       C O D E
;様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様
INT13:


        out     80h, al


    ;    _mcls
    ;    _mshowregs



        cmp     dl, 0                   ; A: drive?
        jnz     real_int13              ; no, skip flopper support.  

        cmp     ah, RESET_DRIVE         ; Reset disk subsystem?
        jz      verify

        cmp     ah, VERIFY_SECTORS      ; verify sectors?
        jz      verify

        cmp     ah, WRITE_SECTORS       ; writing sectors?
        jz      write

        cmp     ah, READ_SECTORS        ;
        jnz     real_int13              ; send everything else to BIOS

read:
        push    di
        call    disk_changed?           ; has floppy been removed on us?
        jc      exit_int13
        call    select_disk             ; set up EDI to point to start of disk
        call    valid_sector?           ; check to see if sector is available
        jc      exit_int13
        call    sector2offset           ; translate parameters to offset
        call    readSectors             ; fill buffer with required data
        jmp     exit_int13

write:
        ; could do all the setup work then figure out if we're reading or
        ; writing to memory to optimize code.  maybe next time.

        push    di
        call    disk_changed?           ; has floppy been removed on us?
        jc      exit_int13
        call    disk_writeprotected?    ; can we write?
        jc      exit_int13
        call    select_disk             ; set up EDI to point to start of disk
        call    valid_sector?           ; check to see if sector is available
        jc      exit_int13
        call    sector2offset           ; set up target buffer
        call    writeSectors            ; write data to image
        call    update_writeflag        ; set flag for exit
        jmp     exit_int13

verify:
        push    di
        clc                             ; uh, yep, everything "verified" ok!
        mov     ah, NO_DISK_ERROR

exit_int13:
        pop     di                      
        sti
        retf 2

real_int13:

        jmp     realInt13               ; call real INT13
;----------------------------------------------------------------------------
;procedure: sect2offset
;purpose: converts an int 13 sector request to an offset in the image file
;procedure wants: standard INT 13h call format (CH=track,CL=sector#,DH=head)
;                 EDI=pointer to disk's parameter table      
;procedure returns: EDI=offset in file where "sector" begins
;procedure destroys: just about everything.  
;============================================================================
sector2offset proc near

    ;algoryrythym:  offset=track*SectorsPerTrack*Heads
    ;                      +head*SectorsPerTrack
    ;                      +sectorNumber
    ;offset=offset*512, assuming 512 byte sectors.


        push    ax
        push    bx
        push    cx
        push    dx
        push    si

        ; calculate sectorsPerTrack * Heads

        push    cx
        mov     al, byte ptr gs:[edi+1]         ; read SPT
        mov     cl, byte ptr gs:[edi]           ; read heads
        dec     cl
        shl     al, cl                          ; multiply by heads
        pop     cx

        ; multiply * track number (CH)

        push    cx
        xor     ah, ah
        xor     cl, cl
        xchg    cl, ch
        mul     cl
        pop     cx

        ; AX=track#*sector/track*heads

        
        shl     eax, 16                         ; save AX
        mov     al, byte ptr gs:[edi+1]         ; read SPT again
        xor     dl, dl
        xchg    dh, dl
        mul     dl      

        ; AX=head*sector/track


        dec     cl                              ;start with 0 based sector
        xor     ch, ch
        add     cx, ax
        shr     eax, 16                         ; restore ax
        add     ax, cx


        ; AX is now equal to the sector offset in the file


        add     edi, 4                          ; move beyond disk params

        mov     dx, SECTOR_SIZE
        xor     cx, cx
        xor     bx, bx
        mul     dx                              ; multiply sector size

        mov     si, dx                          ; move offset into EDI
        shl     esi,16
        mov     si, ax

        add     edi, esi

        pop     si
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        ret
sector2offset endp


;----------------------------------------------------------------------------
;procedure: read_sectors
;purpose: reads a "sector" from image file
;procedure wants: INT 13 stuff , head,sector,track,etc ES:BX=buffer for data
;               EDI points to disk's parameter table.
;procedure returns: buffer filled with data, carry flag clear if no error
;procedure destroys: EDI
;notes:  
;============================================================================
readSectors proc near

        ; AL should be the number of sectors to read
        ; ES:BX = pointer to target buffer
        ; EDI = pointer of source buffer
        ; copy SECTOR_SIZE bytes, AL times

        push    ax
        push    bx
        push    cx
        push    edx

        xor     ah, ah
        mov     cx, SECTOR_SIZE / 4
        mul     cx

        mov     cx, ax        

readloop:
        mov     edx, gs:[edi]
        mov     es:[bx], edx
        add     edi, 4
        add     bx, 4
        loop    readloop

        pop     edx
        pop     cx
        pop     bx
        pop     ax
        mov     ah, NO_DISK_ERROR                  ; return no errors
        clc
        ret

readSectors endp

;----------------------------------------------------------------------------
;procedure: write_sectors
;purpose: writes data to a "sector" in image file
;procedure wants: INT 13 stuff , head,sector,track,etc ES:BX=buffer for data
;               EDI points to disk's parameter table.
;procedure returns: buffer filled with data, carry flag clear if no error
;procedure destroys: EDI
;notes:  
;============================================================================
writeSectors proc near

        ; AL should be the number of sectors to read
        ; ES:BX = pointer to source buffer
        ; EDI = pointer of target buffer
        ; copy SECTOR_SIZE bytes, AL times

        push    ax
        push    bx
        push    cx
        push    edx

        xor     ah, ah
        mov     cx, SECTOR_SIZE / 4
        mul     cx

        mov     cx, ax        

writeloop:
        mov     edx, es:[bx]
        mov     gs:[edi], edx
        add     edi, 4
        add     bx, 4
        loop    writeloop

        pop     edx
        pop     cx
        pop     bx
        pop     ax
        mov     ah, NO_DISK_ERROR                  ; return no errors
        clc
        ret

writeSectors endp

;------------------------------------------------------------------------
; reads current disk # and points EDI to start of diskette image -4.
;
select_disk     proc    near
        mov     edi, DISK_START
        add     edi, 4                  ; point beyond disk size
        ret
select_disk endp


;------------------------------------------------------------------------
; check if the selected sector is beyond the disk.  Ie, reading sector
; 10 on a 9 sector/track disk.
valid_sector?   proc    near

        push    ax
        sub     al, 1                   ; make 0 based
        jc      sector_not_found        ; 
        add     al, cl                  ; add starting sector with # of sec.
        cmp     al, byte ptr gs:[EDI+1] ; bigger than sectors/track?
        pop     ax
        ja      sector_not_found        ; bail!
        push    es
        push    bx
        les     bx, gs:[(1Eh*4)]  ; load disk param table into es:bx
        cmp     byte ptr es:[bx+3], 2   ; sector size
        pop     bx
        pop     es
        jne     sector_not_found
        clc
        ret
sector_not_found:
        mov     ah, SECTOR_NOT_FOUND_ERROR
        xor     al, al
        stc
        ret
valid_sector?   endp

disk_writeprotected? proc near
; set carry if diskette is write protected.
        push    si
        xor     si, si
        test    cs:[si].flagbyte, DISK_PROTECTED
        clc
        jz      ok2write
        stc     
        mov     ah, DISK_WP_ERROR
ok2write:
        pop     si
        ret
disk_writeprotected? endp




update_writeflag proc near
; set flag byte to show image changed
        push    si
        xor     si, si
        or      cs:[si].flagbyte, DISK_WRITTEN
        pop     si
        ret
update_writeflag endp



disk_changed? proc near
;returns carry set and error status if disk has changed.
        push    si
        xor     si, si
        clc                     ; assume no
        test    cs:[si].flagbyte, DISK_CHANGE
        jz      nochange
        mov     ah, DISK_CHANGED_ERROR
        and     cs:[si].flagbyte, NOT DISK_CHANGE   ; turn off status          
        stc     
nochange:
        pop     si
        ret
disk_changed? endp


;様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様
;        I N T E R R U P T        1 5 h       C O D E
;様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様
; intercept INT 15, ah=4f to snag keyboard stuff. called by INT 9
;

INT15:
        call    realInt15



        pushf
        cmp     al, F12_SCAN_CODE
        jnz     exit_int15
        popf


      ;  call    saveregs                 ; future, never restores regs yet.


        out     80h, al





        ; prepare to enter chooser
        ; the video page, mode and cursor position need to be saved before
        ; memory is swapped out.
        ; these items need to be restored 
      
        push    ax
        push    bx
        push    cx
        push    dx
        push    si
        xor     si, si
        mov     ah, 0fh
        int     10h
        
        mov     cs:[si].vidmode, al
        mov     cs:[si].vidpage, bh

        mov     ah, 03
        int     10h                                     ; get cursor position
        mov     cs:[si].cursorpos, dx       ; save it


        pop     si
        pop     dx                       
        pop     cx
        pop     bx
        pop     ax



        _swap512k


        ; jump to chooser
        push    bx
        push    ax

        push    si
        xor     si, si
        mov     al, cs:[si].flagbyte    ; retrieve status
        mov     bl, cs:[si].vidmode
        mov     bh, cs:[si].vidpage
        pop     si

        int     03fh                    ; invoke chooser

        push    si
        xor     si, si
        mov     cs:[si].flagbyte, al    ; return status
        pop     si

        pop     ax
        pop     bx



        push    ax
        push    bx
        push    cx
        push    dx
        push    si
        xor     si, si


        mov     bh, cs:[si].vidpage   ; bl=mode bh=page
        mov     dx, cs:[si].cursorpos ; get cursor position
        mov     ah, 02
        int     10h                      ; set cursor position


        pop     si
        pop     dx                       
        pop     cx
        pop     bx
        pop     ax


    ;    pop     bx

        _swap512k
        sti



       ; call    restoreregs

        pushf
exit_int15:
        popf
        iret
;---------------------------------------------------------------------------
;saveregs.  copies all registers into high memory for later restoring
;without a stack.
;chooser MUST restore any 32 bit registers used!

saveregs proc near          
        push    edi
        push    esi
        rol     esi, 16
        mov     di, si

        mov     edi, REGS_START
        mov     word ptr gs:[edi], ax
        add     edi, 2
        mov     word ptr gs:[edi], bx
        add     edi, 2
        mov     word ptr gs:[edi], cx
        add     edi, 2
        mov     word ptr gs:[edi], dx
        add     edi, 2
        mov     word ptr gs:[edi], cs
        add     edi, 2
        mov     word ptr gs:[edi], ds
        add     edi, 2
        mov     word ptr gs:[edi], es
        add     edi, 2
        mov     word ptr gs:[edi], ss
        add     edi, 2
        mov     word ptr gs:[edi], sp
        add     edi, 2
        mov     word ptr gs:[edi], bp
        add     edi, 2
        mov     word ptr gs:[edi], si           ; save di
        ror     esi, 16
        add     edi, 2
        mov     word ptr gs:[edi], si           ; save si
        add     edi, 2

        push    ax
        pushf
        pop     ax
        mov     word ptr gs:[edi], ax           ; save flags
        pop     ax


        pop     esi
        pop     edi
        ret

saveregs endp


;様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様
;        I N T E R R U P T        5       C O D E 
;様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様
; screenshot.
INT5:

        ; copy palette byte from 40:65 and put it into b800:3ffff
        ; b800:3fff is not used on the screen, so it is safe to place a
        ; byte here without modifying screen contents.

        push    ax
        push    es
        push    di

        mov     al, gs:[465h]

        mov     di, 0b800h
        mov     es, di
        mov     di, 3fffh

        stosb

        pop     di
        pop     es
        pop     ax
       
        _swap512k

        ; jump to chooser
        push    si
        xor     si, si
        mov     al, cs:[si].flagbyte    ; retrieve status
        pop     si
        or      al, SCREENSHOT

        int     03fh                    ; invoke chooser

        push    si
        xor     si, si
        mov     cs:[si].flagbyte, al    ; return status
        pop     si


      ; do we need this stuff here?
        
        ; signal end of interrupt
        push    ax
        mov     al, 20h
        out     20h, al
        out     0a0h, al
        out     20h, al

        int     9
      ;
        pop     ax
        _swap512k

        iret

;様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様
;        I N T E R R U P T        70h       C O D E 
;様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様
INT70:
   ;     call    revector_int9





        ; check if key is available

        push    ax


        test    byte ptr gs:[417h], BIT0
        jz      exit_int70
        
        test    byte ptr gs:[417h], BIT1
        jz      exit_int70

        push    bx
        mov     ah, 0fh
        int     10h
        mov     ah, bh                   ; al=mode
        pop     bx                       ; ah=page
        

        _swap512k

        push    bx
        mov     bx, ax                   ; pass mode and page into chooser
                                         ; via BX

        ; signal end of interrupt
;        mov     al, 20h
 ;       out     20h, al
 ;       out     0a0h, al
 ;       out     20h, al
;
   ;     int     9
      ; 
        ; jump to chooser
        push    si
        xor     si, si
        mov     al, cs:[si].flagbyte    ; retrieve status
        pop     si

        int     03fh                    ; invoke chooser

        push    si
        xor     si, si
        mov     cs:[si].flagbyte, al    ; return status
        pop     si

 ;
 ;       pop     bx

        _swap512k
        int     9



exit_int70:
        cli                       
        mov     al, 0ch                ; read cmos status register 
        out     70h, al                ; which signals RTC that it can generate
        in      al, 71h                ; INT 70 again
        sti

        mov     al, 20h                ; signal end of interrupt
        out     20h, al
        out     0a0h, al               
        out     20h, al


        pop     ax
        iret


     ;   in      al, 80h
     ;   mov     ah, al
     ;
     ;   shl     ah, 1
     ;   cmp     ah, 8
     ;   jz      reset
     ;
     ;   mov     al, 0edh
     ;   out     60h, al
     ;   push    cx
     ;   xor     cx, cx
     ;   loop    $
     ;   loop    $
     ;   loop    $
     ;   loop    $
     ;   pop     cx

    ;    mov     al, ah
    ;    out     60h, al

    ;    out     80h, al
    ;    jmp     done

;reset:  
  ;      mov     al, 1
  ;      out     80h, al



;done:
;        sti
;        pop     ax
;
;        iret



revector_int9   proc    near
     ;   test    cs:[0], REVECTORED
     ;   jnz     no_revector

        push    edx
        mov     dx, word ptr gs:[9h*4+2]


        push    ax
        push    cs
        pop     ax

        cmp     dx, ax
        pop     ax

        jz      fok2

        push    ax
        mov     al, 0
        out     80h, al
        pop     ax
fok2:




        cli
        mov     edx, dword ptr gs:[09h*4]
        mov     dword ptr gs:[0Fdh*4], edx
        mov     edx, dword ptr gs:[0FEh*4]       ; read our int 9 vector
        mov     dword ptr gs:[09h*4], edx       ; replace INT 9 vector
        sti
        pop     edx
     ;   or      byte ptr cs:[0], REVECTORED
no_revector:
        ret
revector_int9   endp


keyboard_read   proc    near
        cli
        in      al, 64h
        test    al, 1
        jz      exit_key_read


        in      al, 60h
        xor     ah, ah

exit_key_read:
        sti
        ret
keyboard_read   endp

comment %
old crappy code!

; cpu slowdown, revectorerer.
INT70:
   ;     call    revector_int9

        test    byte ptr gs:[417h], BIT0
        jz      exit_int70
        
        test    byte ptr gs:[417h], BIT1
        jz      exit_int70

        call    rtc_off2                ; disable RTC from firing while here.



        push    ax

        push    bx
        mov     ah, 0fh
        int     10h
        mov     ah, bh                   ; al=mode
        pop     bx                       ; ah=page
        

        _swap512k

        push    bx
        mov     bx, ax                   ; pass mode and page into chooser
                                         ; via BX

        ; signal end of interrupt
        mov     al, 20h
        out     20h, al
        out     0a0h, al
        out     20h, al
;
        int     9
      ; 
        ; jump to chooser
        
        mov     al, cs:[0]              ; retrieve status
        int     03fh                    ; invoke chooser
        mov     cs:[0], al              ; return status
 ;
        int     9
        pop     bx

        _swap512k
        sti

        ; signal end of interrupt again?
        mov     al, 20h
        out     20h, al
        out     0a0h, al
        out     20h, al
        pop     ax

exit_int70:

        call    rtc_on

        push    ax
        cli
        mov     al, 0ch                ; read cmos status register 
        out     70h, al                ; which signals RTC that it can generate
        in      al, 71h                ; INT 70 again
        sti

        mov     al, 20h                ; signal end of interrupt
        out     20h, al
        out     0a0h, al               
        out     20h, al

        pop     ax
        iret


     ;   in      al, 80h
     ;   mov     ah, al
     ;
     ;   shl     ah, 1
     ;   cmp     ah, 8
     ;   jz      reset
     ;
     ;   mov     al, 0edh
     ;   out     60h, al
     ;   push    cx
     ;   xor     cx, cx
     ;   loop    $
     ;   loop    $
     ;   loop    $
     ;   loop    $
     ;   pop     cx

    ;    mov     al, ah
    ;    out     60h, al

    ;    out     80h, al
    ;    jmp     done

;reset:  
  ;      mov     al, 1
  ;      out     80h, al



;done:
;        sti
;        pop     ax
;
;        iret



revector_int9   proc    near
     ;   test    cs:[0], REVECTORED
     ;   jnz     no_revector

        push    edx
        mov     dx, word ptr gs:[9h*4+2]


        push    ax
        push    cs
        pop     ax

        cmp     dx, ax
        pop     ax

        jz      fok2

        push    ax
        mov     al, 0
        out     80h, al
        pop     ax
fok2:




        cli
        mov     edx, dword ptr gs:[09h*4]
        mov     dword ptr gs:[0Fdh*4], edx
        mov     edx, dword ptr gs:[0FEh*4]       ; read our int 9 vector
        mov     dword ptr gs:[09h*4], edx       ; replace INT 9 vector
        sti
        pop     edx
     ;   or      byte ptr cs:[0], REVECTORED
no_revector:
        ret
revector_int9   endp


keyboard_read   proc    near
        cli
        in      al, 64h
        test    al, 1
        jz      exit_key_read


        in      al, 60h
        xor     ah, ah

exit_key_read:
        sti
        ret
keyboard_read   endp
rtc_off2 proc near
;disables the real time clock periodic timer

        push    ax
        cli
        mov     al, 0bh
        out     70h, al
        in      al, 71h
        mov     ah, al          
        and     ah, NOT BIT6    ; turn off BIT 6 in CMOS status register 0Bh
        mov     al, 0bh         ; which generates IRQ 8 to call INT 70
        out     70h, al
        mov     al, ah
        out     71h, al

        sti
        pop     ax
        ret
rtc_off2 endp



rtc_on  proc near
        push    ax
        cli
        mov     al, 0bh
        out     70h, al
        in      al, 71h
        mov     ah, al
        or      ah, BIT6         ; turn on BIT 6 in CMOS status register 0Bh
        mov     al, 0bh          ; which generates IRQ 8 to call INT 70
        out     70h, al          
        mov     al, ah
        out     71h, al
        sti
        pop     ax
        ret
rtc_on  endp
%
;様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様
;        I N T E R R U P T        9       C O D E
;様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様
INT9:
        int     0FDh                            ; call old INT 9
        push    ax
        mov     ah, 4fh
        int     15h
        pop     ax
        iret
flopper_bottom:

