ver1    EQU     "1"
ver2    EQU     "0"
ver3    EQU     "2"


comment %
release version 1.0.2  06/04/02

See history.txt for revision notes and differences.

        
floppy diskette boot emulator  (aka flopper)
jeff leyda
jeff@silent.net


flat real mode memory routines written by NiX / MASSiVE
cpu id code comes from the book "undocumented PC"
chooser portion written by demonlord


the following code and concept are to remain in the public domain as
freeware to be used and modified by anyone who choses to use it.
please don't be a dick and steal the code and try to sell it! 

compiled with TASM 3.0, linked with MS-LINK 5.10
will compile with TLINK using the /3 option.
will also compile with MASM/LINK

main documentation for program usage can be found in the file INSTALL.HTM
or INSTALL.TXT


様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様
memory map:

        0:0 -> 512k             DOS/game
        513k -> ?               flopper suport routines
        1mb -> 1mb+512k         DOS/game  (1mb defined in equates.inc)
        1mb+512k - >1mb+513k    registers/reserved space
        1mb+513k - >xxx         disk image
        
様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様

TODO:
       .support for 128 and 1k and 2k byte sector sizes
       .better keyboard intercept routines.  some games don't like the
         intercept that i'm doing right now.  (jumpman)
       .shell to dos feature from within chooser

%
STAPEL SEGMENT STACK USE16 'Stack'
dw 200 dup(?)
STAPEL ENDS

CODE SEGMENT USE16
Assume cs:code, ss:stapel



;陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳
; Include files
;陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳陳
include constant.inc    ; Stuff that never changes.
include equates.inc     ; run time and compile time variables
;include debug.inc       ; debugger support.  Not really needed for now.
include flatmem.inc     ; Generic Memory and Flat Real Mode routines
include revector.inc    ; interrupt vector table loading routines
include cpu.inc         ; detect CPU code support
include diskette.inc    ; diskette definitions and code
include fileio.inc      ; file opening, closing, etc code
include cmdline.inc     ; command line input routines
include flopisr.inc     ; flopper ISR support code
include scrnshot.inc    ; screenshot support code
include rtc.inc         ; real time clock/cpu slowdown routines
include version.inc     ; display version# routines
include vidstuff.inc	; video code
include misc.inc	; odds and ends
;様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様
;                          MAIN CODE STARTING POINT
;様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様
Start:

        ; system checks, get into flat memory model

        call    check_cpu               ; requires at least a 386. 
        call    check_himem             ; no himem.sys!       
        call    check_2mb               ; requires at least 2mb
        call    Set4Gig                 ; Swap to Flat Real Mode
        call    EnableA20               ; Enable the A20-line
	call    displayVersionMsg       ; display version message

        cli
        mov     cs:[ss_val], ss         ; save current SS:SP
        mov     cs:[sp_val], sp
        sti

        ; put chooser at INT 3F
        push    es
        push    cs
        pop     es
        lea	dx, oldint3F
	mov     bx, offset chooser
        mov     al, 03fh
        call    changeISR
        pop     es

        ; check files, load image
	call    process_cmdline         ; grab filenames, switches, etc
	test	cmdlineflags, help
	jnz	display_help

	call    open_file               ; open file if exists
        jnc     open_ok
      ;  call    loadErrorMsg            ; file load error, jump directly 
        jmp     chooser	              	; into chooser
        jmp     exit
open_ok:
        call    get_disk_params         ; return disk image Spt/H/T info
        call    load_image              ; load diskette image
        call    close_file              ; close 
        call    getPICMask              ; read current PIC mask

reboot:
        call    reset_pic               ; reset the PIC
        call    setdelayamount          ; copy initial delay value to 512k
        call    put512high              ; copy DOS area high in memory
	mov     al, " "                 ; DOS grey
        mov     ah, 7
	call	cls			; clear the screen
      ;  call    printload               ; print loading message

        ; prepare for boot              

        call    change_base_size        ; set BDA memory size to 512k
	call    copy_code               ; load flopper support above 512k
        call    reset_vectors           ; load virgin vector table

        ; figure out starting location of new INT service
        ; move this to a subroutine too.

	mov     si, offset flopper_top  ; point to start of flopper routines
        mov     bx, offset int13        ; point to start of new INT13
        sub     bx, si                  ; from offset of flopper_top
        mov     dx, offset realInt13    ; point to storage for old INT13
        inc     dx                      ; add 1 for "db EA" instruction.
        sub     dx, si
        mov     al, 13h
        call    changeISR

        mov     si, offset flopper_top  ; point to start of flopper routines
        mov     bx, offset int15        ; point to start of new INT15
        sub     bx, si                  ; from offset of flopper_top
        mov     dx, offset realInt15    ; point to storage for old INT15
        inc     dx                      ; 
        inc     dx
        sub     dx, si
        mov     al, 15h
        call    changeISR


        mov     si, offset flopper_top  ; point to start of flopper routines
        mov     bx, offset int5         ; point to start of new INT5
        sub     bx, si                  ; from offset of flopper_top
        mov     dx, offset realInt5     ; point to storage for old INT5
        inc     dx                      ; add 1 for "db EA" instruction.
        sub     dx, si
        mov     al, 5
        call    changeISR
   	
        test	cmdlineflags, nocache                             
	jnz	@f
	call    disable_cache           ; turn off L1 Cache if 486+   
@@:
   	test	cmdlineflags, nodelay
	jnz	@f

        mov     si, offset flopper_top
        mov     bx, offset int70
        sub     bx, si
        mov     al, 70h
        call    changeISR
   
        call    slowdown_cpu            ; throttle back to 4.77MHz
                                        ; can't start this until INT 70
                                        ; vector is in place cuz Int70 will
                                        ; start immediately after this call.
@@:        
        ; "load" disk!
        
        xor     ax, ax
        mov     es, ax                  ; load 1st sector to 0:7c00
        mov     bx, 7c00h
        mov     ah, 2                   ; read
        mov     al, 1                   ; 1 sector
        mov     ch, 0                   ; track 0
        mov     cl, 1                   ; sector 1
        mov     dh, 0                   ; head 0
        mov     dl, 0                   ; drive 0 (a:)
        int     13h                     

        xor     ax, ax
        mov     bp, ax                  ; set up registers like they would
        mov     ds, ax                  ; be for "booting"
        mov     ss, ax
        mov     sp, 400h

        push 0                          ; jump to 0:7c00 to "boot" diskette
        push 7c00h
        retf

display_help:

	call	mode50

	mov	ah, 9
	lea	dx, helpmsg			; display help message
	int	21h
	
	mov	ax, 4c02h			; end
	int	21h

;様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様
;                          CHOOSER STARTING POINT
;様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様様
cmdlineflags	db	0
oldint3f	dd	?			; storage for 3F vector
versionmsg      db      "Flopper ver ",ver1,".",ver2,".",ver3,CR,LF,"$"

helpmsg		db	CR,LF,"Command line usage:",CR,LF
		db	"/? /H display this message",CR,LF
		db	"/C - do not disable L1 CPU cache.",CR,LF
                db      "/F - do not enable floppy delay emulation.",CR,LF
		db	"/N - do not enable RTC CPU throttle.",CR,LF
                db      "/P - do not reset the interrupt controller (PIC).",CR,LF
		db	"/Ix - set delay interval value (x=3-F) see below.",CR,LF
		db	"/Dx - set delay value x (x=1-F) see below.",CR,LF
		db	CR,LF
		db	"Examples:",CR,LF
		db	"flopper /N bcwolf.img",CR,LF
		db	"flopper /C /D3 jumpman.img",CR,LF
		db	"flopper /D2 /I6 frogger.img",CR,LF,CR,LF

		db	"Interval values:",CR,LF
		db	"F = 500mS pulse    (2 per second)",CR,LF
		db	"E = 250mS pulse    (4 per second)",CR,LF
		db	"D = 125mS pulse    (8 per second)",CR,LF
		db	"C = 62.5mS pulse   (16 per second)",CR,LF
		db	"B = 31.25mS pulse  (32 per second)",CR,LF
                db      "A = 15.625mS pulse (64 per second)",CR,LF
		db	"9 =  7.8mS pulse   (128 per second)",CR,LF
		db	"8 =  3.9mS pulse   (256 per second)",CR,LF
		db	"7 =  1.95mS pulse  (512 per second)",CR,LF
		db	"6 =  0.976mS pulse (1024 per second)",CR,LF
		db	"5 =  0.488mS pulse (2048 per second)",CR,LF
		db	"4 =  0.244mS pulse (4096 per second)",CR,LF
                db      "3 =  0.122mS pulse (8192 per second) Default",CR,LF
		db	"2-0 Unsupported.",CR,LF,CR,LF

		db	"Delay values:",CR,LF
		db	"Any value between 1 and F",CR,LF
                db      "This value controls the number of 1/4mS delays per interval",CR,LF
                db      "Default delay value is 4.",CR,LF,"$"



chooser_msg     db      "Welcome to chooser!",CR,LF
                db      "Current Image is:$"

delaymsg	db	CR,LF,"Delay amount:$"

chooser_msg2    db      CR,LF,CR,LF,"Select:",CR,LF
                db      " 1. load image",CR,LF
                db      " 2. save image",CR,LF
                db      " 3. Write $"

chooser_msg3    db      " disk",CR,LF
                db      " 4. Boot current image",CR,LF
                db      " 5. Return to image",CR,LF
                db      " 6. Increase delay amount",CR,LF
                db      " 7. Decrease delay amount",CR,LF
                db      "ESC Exit to DOS$"


prot_msg        db      "protect$"
enab_msg        db      "enable$"

ss_val          dw      0       ; storage for Stack segment
sp_val          dw      0       ; and pointer
ss_ret          dw      0       ; storage for returned stack segment
sp_ret          dw      0       ; and pointer
flags           db      0
delay		db	0	; current delay amount
interval	db	delay_8192
fname           db      76 dup(0)
newfilestr      db      CR,LF,CR,LF,'Enter new image filename: $'
warning_msg     db      CR,LF,"Warning! Disk image was written!",CR,LF
                db      "Changes will be lost!  Press ESC again to exit$"        
cga_reg         dw      ?       ; storage for 3d8, 3d9 register
mode_page       dw      ?       ; storage for video mode and page
chooser:

	cmp	cs:[delay], 0
	jz	@f

        cli
        mov     cs:[ss_ret], ss              ; save game SS:SP
        mov     cs:[sp_ret], sp
        mov     ss, cs:[ss_val]              ; restore flopper SS:SP
        mov     sp, cs:[sp_val]
        sti
@@:
        pusha
        push    ds
        push    es

        push    cs				; reset segment registers
        push    cs
        pop     ds
        pop     es

	cmp	cs:[delay], 0			; entering chooser from cmd
	jz	first_chooser			; line?  


        ; signal end of interrupt
        push    ax
        mov     al, 20h
        out     20h, al
        out     0a0h, al
        out     20h, al
        pop     ax
        int     9
        
      ;

      	mov	cs:[delay], ah			; save flopper delay amount  
        mov     cs:[flags], al                  ; save flopper flags
        mov     cs:[mode_page], bx              ; save video info

        test    al, SCREENSHOT
        jz      chooser_menu

        call    do_screenshot
        jmp     exit_chooser

first_chooser:

        mov     cs:[delay], 4                   ; kludge delay value to 1

chooser_menu:

        call    savescreen
        mov     dx, CGA_CONTROL_REGISTER
        in      ax, dx
        mov     [cga_reg], ax
getselect:
       	mov     bx, 0
        mov     ax, 3
        int     10h
        
    	lea     dx, chooser_msg
        mov     ah, 9
        int     21h


        ;print current image filename

        lea     di, fname
        mov     ax, 1212h
        int     2Fh

        add     di, cx
        mov     byte ptr [di],"$"

        lea     dx, fname
        mov     ah, 9
        int     21h
        mov     byte ptr [di],0                 ; restore name to asciiz

	lea	dx, delaymsg
	int	21h

	mov	al, cs:[delay]
	xor	ah, ah
	call	hex2dec
	mov	cx, 2
	call	printreg


	mov	ah, 9
        lea     dx, chooser_msg2
        int     21h


        test    byte ptr flags, DISK_PROTECTED
        jz      wpenabled

        lea     dx, enab_msg
        int     21h
        jmp     msg3

wpenabled:
        
        lea     dx, prot_msg
        int     21h

msg3:
        
	mov	ah, 09
	lea     dx, chooser_msg3
        int     21h
        mov     ax, word ptr gs:[41ch]          ; clear keyboard buffer
        mov     word ptr gs:[41ah],ax
	
        xor     ax, ax
        int     16h

        cmp     al, ESCAPE
        jz      check_written

        cmp     al, "1"                         ; load new image
        jz      load_disk

        cmp     al, "2"                         ; save current image to HDD
        jz      save_disk

        cmp     al, "3"                         ; write protect current image
        jz      wp_toggle

        cmp     al, "4"                         ; reboot current image
        jz      reboot

        cmp     al, "5"                         ; nothing.
        jz      restoreandexit

	cmp	al, "6"
	jz	moredelay

	cmp	al, "7"
	jz	lessdelay

        cmp     al, CR
        jz      restoreandexit

        jmp     getselect

save_disk:
        lea     dx, fname
        call    save_image
        and     flags, NOT DISK_WRITTEN         ; update image written flag
        jmp     getselect

wp_toggle:

        xor     flags, DISK_PROTECTED
        jmp     getselect

check_written:
        test    flags, DISK_WRITTEN
        jz      exit

        mov     ah, 9
        lea     dx, warning_msg
        int     21h

        xor     ax, ax
        int     16h
        cmp     al,ESCAPE
        jnz     getselect
        jmp     exit


load_disk:
        mov     ah, 9
        lea     dx, newfilestr
        int     21h

        lea     di, fname       ;Filename buffer

newkey:
        xor     ax,ax
        int     16h
        cmp     al,ESCAPE
        jz      Exit
        cmp     al,13           ;Enter
        jz      NewFile
        cmp     al,8            ;Backspace
        je      Erase
        cmp     al,32           ;Space+
        jb      newkey

        cmp     di,offset FName+75     ;Not too long??
        ja      newkey
        stosb                   ;Store character
        mov     ah,0eh
        mov     bx,7
        int     10h             ;Show character entered
        jmp     newkey

Erase:
        cmp     di,Offset FName
        jbe     NewKey          ;Check length
        mov     ah,3
        mov     bh,0
        int     10h             ;Get cursor pos
        dec     dl
        push    dx
        mov     ah,2
        int     10h             ;Move one step left
        mov     ax,0e20h
        mov     bx,7
        int     10h             ;Erase current char
        pop     dx
        mov     ah,2
        int     10h             ;Restore cursor pos
        dec     di              ;Remove last char from buffer
        jmp     NewKey

NewFile:
        cmp     di,Offset FName
        jbe     Exit_chooser            ; Nothing entered

        mov     al, 0                   ; null terminate
        stosb

        lea     dx, fname

        call    open_file               ; open file if exists
        jnc     @f
	call	loadErrorMsg		; print file not found message.
	jmp	getSelect		; back to chooser
@@:
        call    get_disk_params         ; return disk image Spt/H/T info
        call    load_image              ; load diskette image
        call    close_file              ; close
        or      flags,DISK_CHANGE       ; set diskchange flag
        jmp     getselect               
                

moreDelay:
	inc	byte ptr cs:[delay]
	jmp	getSelect

lessDelay:
	dec	byte ptr cs:[delay]
	cmp	cs:[delay], 0
	ja	@f
	mov	cs:[delay], 1
@@:
	jmp	getSelect



restoreandexit:

        mov     ax, mode_page
        xor     ah, ah
        int     10h

        mov     ax, mode_page
        xchg    al, ah
        mov     ah, 05
        int     10h


        call    restorescreen           ; restore video data

        mov     dx, CGA_CONTROL_REGISTER
        mov     ax, [cga_reg]
        out     dx, ax
  

exit_chooser:

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

        pop     es
        pop     ds
        popa

        cli
        mov     ss, cs:[ss_ret]
        mov     sp, cs:[sp_ret]
        sti

        mov     al, cs:[flags]
	mov	ah, cs:[delay]
        iret


exit:
        call    restore_cache           ; re-enable L1 cache if need be
        call    rtc_off
        call    reset_pic               ; reprogram the PIC
        ; signal end of interrupt
        push    ax
        mov     al, 20h
        out     20h, al
        out     0a0h, al
        out     20h, al
        pop     ax

	mov	ah, 7
	mov	al, " "
	call	cls
        mov     ah, 4ch
        int     21h

endflag:
CODE ENDS
End Start

