;
; GRDP
;
; Copyright(c) LADsoft
;
; David Lindauer, camille@bluegrass.net
;           
;
; OPTIONS.ASM.ASM
;
; Function: Option input and display
;
	;MASM MODE
	.MODEL SMALL
	.386p

NUMOPTS = 11
include  iversion.inc
include  eprints.inc 
include  einput.inc 
include  emtrap.inc 
include  ebreaks.inc 
include  eints.inc
include  elogging.inc

; define the symbol RAWA20 to run flat real mode with XMS
;
	PUBLIC doopt,optdword, optdwordcommand,optpure,opthist, optflat0, optsignedimm
	PUBLIC Disassemble32Bit, optdiv0, winshellchk
	PUBLIC initflatreal, rundownflatreal, optdosio
        PUBLIC ReadOptions, WriteOptions

	.data
;
; gdt for flat real mode
;
gdt	db	8 DUP (0)			;null entry  SEL 0
	db	0ffh,0ffh,0,0,0,92h,0cfh,0	;32-bit dseg SEL 8h
	db	0ffh,0ffh,0,0,0,92h,0,0		;16-bit dseg SEL 10h
gdtp	dw	3 DUP (17h)			;sice of gdt and its pointer
oldgdt  db	6 DUP (?)			;their GDT

;
; optlist, optvals, and optvect MUST be kept in sync
;
optlst	db	"wrfr32zrbknvfif0sohimd"
oldflat0 db	0	; echoes flat0 option so we can leave segs alone
			; on successive ?o if they change them
;
writeopts db	0	;true if options have changed
;
optmark	dw	verid	; MUST preced optvals
optvals	label	BYTE
optdword db	1	;flag if user selected 32-bit registers (WR)
optdwordcommand db 0	;flag if user wants flat real mode (FR)
Disassemble32Bit db	1	;32-bit instructions enabled
	TRUE	equ	1
	FALSE	equ	0
optdiv0	db	1	; these two options DEPEND on VECTLIST
optbrk  db	1	; having the upper bits of the ints set right
			; on a no-param file start
optpure db	1	;native video
optflatinit db	1	;causes init for flat real mode
optflat0 db	0	; flat real mode - default segs to zero
optsignedimm db	0	; set if want to see signed immediates on u command
opthist db	1	;flag if user enabled history
optdosio db	0	; flag if using dos for command I/O
;
optvect	dw	vsetopt,vsetopt,vsetopt
	dw	voptdiv0,voptbrk1b,vsetopt,vsetopt,vsetopt,vsetopt,vsetopt
	dw	vsetopt
optname	db	"grdb.opt",0
	.CODE
;
; for display of states
;
optmsgs	label	BYTE
	db	13,10,"WR - wide registers     ",0
	db	13,10,"FR - flat real commands ",0
	db	13,10,"32 - 32 bit disassembly ",0
	db	13,10,"ZR - divide by zero trap",0
	db	13,10,"BK - ctrl-break trap    ",0
	db	13,10,"NV - native video       ",0
	db	13,10,"FI - flat real autoinit ",0
	db	13,10,"F0 - flat real 0 default",0
	db	13,10,"SO - signed immediates  ",0
	db	13,10,"HI - command history    ",0
	db	13,10,"MD - msdos I/O          ",0
;
; check for windows shell
;
winshellchk PROC
	push si
	mov	ax,1600h	; check for windows func
	int	2fh		; multiplex int
	pop	si
	cmp	al,00h		; windows not installed if = 0
	je	nowin
	cmp	al,80h		; xms (but no windows) if = 80 h
	je	nowin
	pop	ax		; anything else is windowsxx, drop ret addr
	PRINT_MESSAGE	<10,13,"Feature inactive in windows shells">
	clc
nowin:
	ret
	
winshellchk	ENDP

ifdef RAWA20
;
; Routine to wait till KB controller not busy
;
kb_busy proc
    xor cx,cx           ; Loop 65536 times
kb_bs2:
    in al,64h           ; Get status
    jmp $+2
    jmp $+2
    test al,2           ; See if busy
    jz kb_busy_done     ; Not busy any more
    loop kb_bs2
    stc
    ret
kb_busy_done:
    clc
    ret
kb_busy endp
;
; Routine to wait till KB data buffer empty
;
kb_writewait proc
    xor cx,cx           ; Loop 65536 times
kb_rd2:
    in al,64h           ; Get port status
    test al,2           ;
    jz short kb_writewait_done  ; Quit if buffer empty
    loop kb_rd2         ; Wait a while
    stc                 ; Error
    ret
kb_writewait_done:
    clc
    ret
kb_writewait endp
;
; Routine to wait till KB data buffer fll
;
kb_readwait proc
    xor cx,cx           ; Loop 65536 times
kb_rdrd2:
    in al,64h           ; Get port status
    test al,1           ;
    jnz short kb_readwait_done  ; Quit if buffer empty
    loop kb_rdrd2               ; Wait a while
    stc                 ; Error
    ret
kb_readwait_done:
    mov cx,32           ; Wait for controller to set data
delay:
    jmp $+2
    jmp $+2
    loop delay          ;
    clc
    ret
kb_readwait endp
;
; Routine to turn on A20 line
;
seta20  proc
    cli                 ; Don't want a keypress now!
    call kb_busy        ; Wait while busy
    jc short error              ;
    mov al,0d0h         ; Command to get port status
    out 64h,al          ;
    call kb_busy        ; Wait while busy
    jc short error    
    call kb_readwait    ; Wait for it to put the char there
    jc short error
    in al,60h           ; Get the data
    or al,2             ; Set the A20 bit
    xchg al,ah          ; Data to ah
    call kb_busy        ; Wait while busy
    jc short error
    mov al,0d1h         ; Command to put port status
    out 64h,al          ;
    call kb_busy        ; Wait while busy
    jc short error
    call kb_writewait   ; Wait for buffer to empty
    jc short error
    mov al,ah           ; Write the data
    out 60h,al          ;
    clc                 ; No erros
error:
    sti                 ; Keys allowed now
    ret
seta20  endp
endif ; RAWA20
;
;
; init flat real mode
;
initflatreal PROC
	test	[optdwordcommand],1	;check if can init
	jz	ifrx
	test	[optflatinit],1
	jz	ifrx
        smsw    ax              ; test if in a shell
        test    ax,1
        jnz     ifr_err         ; err if so
ifdef RAWA20
        call    seta20          ; same as XMS global alloc
else
        mov     ax,4300h        ; now see if XMS loaded
        int     2fh
        cmp     al,80h
        jnz     ifr_err         ; err if not
        push    es
        mov     ax,4310h        ; get xms driver address
        int     2fh
        push    es              ; put on stack
        push    bx
        mov     ax,300h         ; now global enable HMA
        call    dword ptr [esp] ;
        pop     eax             ; clear stack
        pop     es
                                ; at this point we don't check XMS
                                ; return stat as it always works :)
endif
        sub     eax,eax
	mov	ax,ds
	shl	eax,4
	mov	bx,offset gdt
	movzx	ebx,bx
	add	eax,ebx
	mov	dword ptr [gdtp+2],eax	;save old gdt
	push	ds
	push	es
	sgdt	fword ptr [oldgdt]	;get our gdt
	lgdt	fword ptr [gdtp]	;flat real mode in FS
	mov	eax,CR0
	inc	eax
	mov	CR0,EAX
	mov	bx,8			
	mov	ds,bx
	mov	es,bx
	mov	fs,bx
	dec	eax		; back to real mode
	mov	CR0,eax
	lgdt	fword ptr [oldgdt]	;reload their GDT
	pop	es
	pop	ds
	test	[optflat0],1
	jz	ifrx2
	test	[oldflat0],1
	jnz	ifrx2
	mov	[RegdumpDS],0
	mov	[RegdumpES],0
	mov	[RegdumpFS],0
	mov	[RegdumpGS],0
	; leaves SS and CS alone so we can run programs :).
ifrx2:
	mov	al,[optflat0]
	mov	[oldflat0],al
ifrx:
	ret
ifr_err:
        PRINT_MESSAGE	<13,10,"Error: in DOS shell or XMS not available">
        mov     [optflatinit],0
        ret
initflatreal ENDP
;
; reset descriptors for real mode
;
rundownflatreal PROC
	test	[optdwordcommand],1	;check if can init
	jz	rfrx
	test	[optflatinit],1
	jz	rfrx
;
; we don't have to do lots of checking as the flatinit flag would have
; been cleared if we couldn't make the first transition...
;
	push	ds
	push	es
	sgdt	fword ptr [oldgdt]	;get our gdt
	lgdt	fword ptr [gdtp]	;flat real mode in FS
	mov	eax,CR0
	inc	eax
	mov	CR0,EAX
	mov	bx,16
	mov	ds,bx
	mov	es,bx
	mov	fs,bx
	dec	eax		; back to real mode
	mov	CR0,eax
	lgdt	fword ptr [oldgdt]	;reload their GDT
	pop	es
	pop	ds

rfrx:
	ret
rundownflatreal ENDP
;
; option command
;
doopt	PROC	
	Call	WadeSpace	; Wade till address
	jnz	optlp
	mov	si,offset _text : optmsgs	; no args, print all options
	mov	di,offset optvals
	mov	cx,NUMOPTS
polp:
	call	PrintOption
	loop	polp
	call	LoggingStat
	call	initflatreal
optxit:
	clc
	ret
;
; subroutine to print an option and its enabled/disabled value
;
PrintOption:
	mov	bx,si
	call	olMessage
	test	byte ptr [di],-1
	jnz	dotype
	PRINT_MESSAGE	<9,"disabled">
	jmp	dojoin
dotype:
	PRINT_MESSAGE	<9,"enabled">
dojoin:
	inc	di
frs_lp:
	lods	byte ptr cs:[si]
	or	al,al
	jnz	frs_lp
	ret
;
; comes here to set/reset an option
;
optlp:
	cmp	al,13
	je	doopt		; go back and show vals after the set
	cmp	al,'-'		; check for off command
	pushf
	jz	incpos
	cmp	al,'+'
	jne	noinc
incpos:
	inc	si
noinc:
	call	WadeSpace	; now get the option letters
	jz	opterr
	lodsw
	cmp	ah,13
	je	opterr
	mov	cx,NUMOPTS	; search for them
	mov	di,offset optlst
cmplp:
	scasw
	jz	dovect
	loop	cmplp
opterr:
	add	sp,2		; bad opt, exit with no display
	clc
	ret
dovect:
	mov	[writeopts],1	; changing, need disk update
	neg	cx
	add	cx,NUMOPTS
	movzx	ebx,cx
	popf
	lahf
	and	ah,40h
	xor	ah,40h
	shr	ah,6        	; ah = opt new val
	call	[optvect + ebx*2] ; call handler
	call	WadeSpace
	jmp	optlp    	; get another
doopt	ENDP
;
; option routines
; 
; this one is for basic bools
;
vsetopt PROC
	mov	[bx + optvals],ah
	ret
vsetopt	ENDP
;
; following this we have interrupt enables/disables.
; they run through VECLIST and set the high bit to match the
; bool value
;         
voptbrk1b	PROC
	mov	al,1bh
	jmp	vopttraps
voptbrk1b	ENDP
voptdiv0	PROC
	mov	al,0
voptdiv0	ENDP
vopttraps	PROC
	mov	[bx + optvals],ah
	mov	bl,ah
vopttraps	ENDP
voptrefresh	PROC
	push	si
	mov	si,offset veclist
	call	SetVectAttrib
	pop	si
	ret
voptrefresh	ENDP

;
; write options to disk file
;
WriteOptions	PROC
IFDEF OPTION_EN
	mov	[optmark],verid
	test	[writeopts],0ffh
	jz	wo_x
	call	optcreat
	jc	wo_x
	mov	dx,offset optmark
	mov	cx,NUMOPTS+2
	mov	ah,40h
	int	21h
	jc	wo_x2
	mov	[writeopts],0
wo_x2:
	call	optclose
wo_x:
ENDIF
	ret
WriteOptions	ENDP
;
; read options from disk file
;
ReadOptions	PROC
IFDEF OPTION_EN
	mov	[writeopts],1
	mov	[optmark],-1
	call	optopen
	jc	ro_x
	mov	dx,offset optmark
	mov	cx,2
	mov	ah,3fh
	int	21h
	jc	ro_x2
	cmp	[optmark],verid
	jne	ro_x2
	mov	dx,offset optmark+2
	mov	cx,NUMOPTS
	mov	ah,3fh
	int	21h
	jc	ro_x2
	cmp	ax,NUMOPTS
	jne	ro_x2
	push	bx
	mov	[writeopts],0   ; the option file is read
	mov	bl,[optdiv0]	; now set the attrib bits in veclist
	mov	al,0
	call	voptRefresh
	mov	bl,[optbrk]
	mov	al,1bh
	call	voptRefresh
	call	initflatreal
	pop	bx
nd1bfix:
ro_x2:
	call	optclose
ro_x:
ENDIF
	ret
ReadOptions	ENDP


IFDEF OPTION_EN
;
; generi disk file stuff.  Should probably merge with loader and logger
; routines...
;
OptOpen	PROC
	mov	ax,3d02h
	mov	dx,offset optname
	int	21h
	mov	bx,ax
	ret
OptOpen	ENDP
OptCreat	PROC
	mov	ax,3c00h
	mov	cx,0
	mov	dx,offset optname
	int	21h
	mov	bx,ax
	ret
OptCreat	ENDP
OptClose	PROC
	mov	ah,3eh
	int	21h
	ret
OptClose	ENDP
ENDIF

end