;//*******************************************************************************************
;
;       MHG
;
;       Assembler for screen mode and sound blaster
;
;       (C) 1990 MHG
;
;       ModeX SetMode Written by Themie Gouthas,
;
;
;*******************************************************************************************/
GAP = 1         ;;64

.386


AC_INDEX        equ  03c0h   ;Attribute controller index register
MISC_OUTPUT     equ  03c2h   ;Miscellaneous Output register
SC_INDEX        equ  03c4h   ;Sequence Controller Index
GC_INDEX        equ  03ceh   ; Graphics controller Index
CRTC_INDEX      equ  03d4h   ;CRT Controller Index
DAC_READ_INDEX  equ  03c7h   ;
DAC_WRITE_INDEX equ  03c8h   ;
DAC_DATA        equ  03c9h   ;
INPUT_STATUS_0 equ   03dah   ;Input status 0 register


SCREEN_SEG    equ    0a000h  ;segment of display memory in mode X

MAP_MASK      equ    02h     ;index in SC of Map Mask register
READ_MAP      equ    04h     ;index in GC of the Read Map register
BIT_MASK      equ    08h     ;index in GC of Bit Mask register

OVERFLOW      equ    07h     ; CRTC overflow register index
MAX_SCAN_LINE equ    09h     ; CRTC maximum scan line register index
ADDR_HIGH     equ    0ch     ;Index of Start Address High reg in CRTC
ADDR_LOW      equ    0dh     ;                       Low
CRTC_OFFSET   equ    13h     ; CRTC offset register index
UNDERLINE     equ    14h     ; CRTC underline location register index
MODE_CONTROL  equ    17h     ; CRTC mode control register index
LINE_COMPARE  equ    18h     ; CRTC line compare reg. index (bits 0-7 of
			     ; split screen scan line

AC_MODE_CONTROL equ    10h   ; Index of Mode COntrol register in AC
PEL_PANNING     equ    13h   ; Pel panning register index in AC

PATTERN_BUFFER equ 0fffch    ;offset in screen memory of pattern buffer

TRUE    equ 1
FALSE   equ 0


OK             equ 0
ERROR          equ 1



_DATA		SEGMENT BYTE PUBLIC USE32 'DATA'


crttab		dw 00d06h
		dw 03e07h
		dw 04109h
		dw 0ea10h
		dw 0ac11h
		dw 0df12h
		dw 00014h
		dw 0e715h
		dw 00616h
		dw 0e317h

;;//screenstart	dd 0,06000h
screenstart	dd 0,08000h

segptr		dd 0

screen_no      	dw 0

XREZ = 320
YREZ = 240

X376Y282 label word
	db      0e7h
	db      18
	dw      06e00h  ; horz total
	dw      05d01h  ; horz displayed
	dw      05e02h  ; start horz blanking
	dw      09103h  ; end horz blanking
	dw      06204h  ; start h sync
	dw      08f05h  ; end h sync
	dw      06206h  ; vertical total
	dw      0f007h  ; overflow
	dw      06109h  ; cell height
	dw      0310fh  ;
	dw      03710h  ; v sync start
	dw      08911h  ; v sync end and protect cr0-cr7
	dw      03312h  ; vertical displayed
	dw      02f13h  ; offset
	dw      00014h  ; turn off dword mode
	dw      03c15h  ; v blank start
	dw      05c16h  ; v blank end
	dw      0e317h  ; turn on byte mode
	dw      376
	dw      282

_DATA		ENDS

DGROUP GROUP _DATA



pageinw		macro 	a
		mov 	ah,a
		mov 	dx,03c4h
	    	mov 	al,2
		out 	dx,ax
		endm

bitmask		macro a
		mov ah,a
		mov dx,03ceh
		mov al,8
		out dx,al
		endm

_TEXT           SEGMENT BYTE PUBLIC USE32 'CODE'
    	   	ASSUME  cs:_TEXT,ds:_DATA


public	SetModeX_
public	SwapModeX_
public	CursorOff_

CursorOff_:  	pushad
		mov	cx,0
		mov	bx,24+2
		mov	dl,cl
		mov	dh,bl
		mov	bl,0
		mov	ah,2h
		int	010h
		popad
		ret


;-----------------------------------------------------------------------
; Mode X graphics mode set with a virtual screen
;   logical screen width.
; C near-callable as:
;
;    int x_set_mode(unsigned int mode,unsigned int WidthInPixels);
;
; returns the actual width of the allocated virtual screen in pixels
; if a valid mode was selected otherwise returns -1
;
; Saves virtual screen pixel width in _ScrnLogicalPixelWidth.
; Saves virtual screen byte  width in _ScrnLogicalByteWidth.
; Physical screen dimensions are set in _ScrnPhysicalPixelWidth,
; _ScrnPhysicalByteWidth and _ScrnPhysicalHeight
;
;
; Modes:  0  = 320 x 200  (256 color)  NOTE: Some of these modes require
;         1  = 320 x 240  (256 color)     vertical size adjustment.
;         2  = 360 x 200  (256 color)
;         3  = 360 x 240  (256 color)
;         4  = 320 x 400  (256 color)
;         5  = 320 x 480  (256 color)
;         6  = 360 x 200  (256 color)
;         7  = 360 x 480  (256 color)
;         8  = 360 x 360  (256 color)
;         9  = 376 x 308  (256 color)
;         10 = 376 x 564  (256 color)
;
; Written by Themie Gouthas,
; parts adapted from M. Abrash code.
;------------------------------------------------------------------------
SetModeX_:

	pushad
	cld

  ;;	call  clear_vram

	mov   ax,13h                ; let the BIOS set standard 256-color
	int   10h                   ;  mode (320x200 linear)


	mov   dx,SC_INDEX
	mov   ax,0604h
	out   dx,ax                 ; disable chain4 mode
	mov   ax,0100h
	out   dx,ax                 ; synchronous reset while setting Misc
				    ;  Output for safety, even though clock
				    ;  unchanged

	lea   esi,X376Y282
	lodsb

	or    al,al
	jz    @@DontSetDot
	mov   dx,MISC_OUTPUT
	out   dx,al               ; select the dot clock and Horiz
				  ;  scanning rate
@@DontSetDot:
	mov   dx,SC_INDEX
	mov   ax,0300h
	out   dx,ax               ; undo reset (restart sequencer)


	mov   dx,CRTC_INDEX       ; reprogram the CRT Controller
	mov   al,11h              ; VSync End reg contains register write
	out   dx,al               ; protect bit
	inc   dx                  ; CRT Controller Data register
	in    al,dx               ; get current VSync End register setting
	and   al,07fh             ; remove write protect on various
	out   dx,al               ; CRTC registers
	dec   dx                  ; CRT Controller Index
	cld
	xor   cx,cx
	lodsb
	mov   cl,al

@@SetCRTParmsLoop:
	lodsw                     ; get the next CRT Index/Data pair
	out   dx,ax               ; set the next CRT Index/Data pair
	loop  @@SetCRTParmsLoop

	mov   dx,SC_INDEX
	mov   ax,0f02h
	out   dx,ax               ; enable writes to all four planes

   	mov	edi,0a0000h
	mov	eax,0
   	mov   	ecx,65536            ; # of words in display memory
   	rep   	stosb               ; clear all of display memory



	popad
	ret



SetModeX2_:  	pushad

		mov 	ax,013h
		int 	010h


		bitmask	0ffh
		pageinw	01111b	 		;write to all planes

		push	edi
		push	ecx
		mov	edi,0a0000h
		mov	al,[edi]		;do a read/write to set bitmask
	      	mov	[edi],al

       		mov	ecx,010000h  		;clear 64k
		mov	eax,0
		rep	stosb
		pop	ecx
		pop	edi


		mov 	dx,03c4h
		mov 	al,4
		out 	dx,al
		inc 	dx
		in 	al,dx
		and 	al, not 08h
		or 	al,4
		out 	dx,al

		mov 	dx,03ceh
		mov 	al,5
		out 	dx,al
		inc 	dx
		in 	al,dx
		and 	al,not 010h
		out 	dx,al

		dec 	dx
		mov 	al,6
		out 	dx,al
		in 	al,dx
		and 	al,not 02h
		out 	dx,al

		mov 	dx,03d4h
		mov 	al,014h
		out 	dx,al
		inc 	dx
		in 	al,dx
		and 	al,not 040h
		out 	dx,al

		dec 	dx
		mov 	al,017h
		out 	dx,al
		inc	dx
		in 	al,dx
		or 	al,040h
		out	dx,al


		mov	dx,03d4h
		mov	al,011h
		out	dx,al
		inc	dx
		in	al,dx
		and	al,07fh
		out	dx,al
		dec	dx

		mov	ecx,10
		lea	esi,crttab
@@loop33:	lodsw
		out	dx,ax
		loop	@@loop33      	;reprog

	      	popad
		ret



;
;
;		eax = address of 320*256 screen
;          //  	expects a dummy 320*256 linear
;
;         		378*256

SwapModeX_:     push    ebp
                mov     ebp,esp
		pushad
           ;;     mov     eax,-4h[ebp]
		mov	segptr,eax
	      	mov	ebp,256

 		movzx	ebx,screen_no
		xor 	ebx,1
		mov 	screen_no,bx

	 if 1
		pageinw	1
		mov	esi,0
	      	call	syncplane
	      	pageinw	2
		mov	esi,1
	      	call	syncplane
		pageinw	4
		mov	esi,2
	      	call	syncplane
		pageinw	8
		mov	esi,3
	      	call	syncplane
	   endif

	     	mov 	eax,screenstart[ebx*4]
		mov 	cx,ax
		mov 	dx,03d4h
		mov 	al,0ch
		mov 	ah,ch
		out 	dx,ax  		;swap

loop56r:	mov 	dx,03dah 	;make sure v trace is not occuring
	    	in 	al,dx
	    	test 	al,1000b
	    	jnz 	loop56r

;
;	start address is loaded at the start of v trace
;   	so dont draw on the screen until v trace occurs
;
loop44r:	mov 	dx,03dah
		in 	al,dx  	;wait for vertical retrace to occur
		test 	al,1000b
	     	jz 	loop44r

		popad
		pop ebp
		ret


;
;  		376 = 94 * 4 = 47 *8
;
syncplane:      mov	edi,0a0000h
		movzx	ecx,screen_no
		add	edi,screenstart[ecx*4]
	     	add	edi,7+13*94
		add	esi,segptr

		mov	edx,ebp
@@lp12:		mov	ecx,320			;;320
		shr	ecx,4				;/16

@@loop:      	mov	al,[esi+8]	;pixel 4
		mov	ah,[esi+12]	;pixel 3
		rol	eax,16
	       	mov	al,[esi+0]	;pixel 2
		mov	ah,[esi+4]	;pixel 1
		mov	[edi],eax
		add	edi,4
		add	esi,16
		loop	@@loop
	      	add	edi,14
		dec	edx
		jne	@@lp12

		ret

		mov	eax,0aaaaaaaah
	        mov	edx,ebp
		cmp	edx,256
		je	@@okok

@@lpp:          mov	ecx,320
		shr	ecx,4				;/16
@@lpp2:		mov	[edi],eax
		add	edi,4
		loop	@@lpp2
		add	edi,14
		inc	edx
		cmp	edx,256
		jb	@@lpp

@@okok:		ret


syncplane2:     mov	edi,0a0000h
		movzx	ecx,screen_no
		add	edi,screenstart[ecx*4]
		add	esi,segptr

		mov	ecx,XREZ
		imul	ecx,YREZ
		shr	ecx,4				;/16

@@loop111:     	mov	al,[esi+8]	;pixel 4
		mov	ah,[esi+12]	;pixel 3
		rol	eax,16
	       	mov	al,[esi+0]	;pixel 2
		mov	ah,[esi+4]	;pixel 1
		mov	[edi],eax

		add	edi,4
		add	esi,16

		loop	@@loop111
		ret

_TEXT	   	ENDS



;-------------------------------------------------------------------------------------------------------------------;
;                                                                                                                   ;
;                                                                                                                   ;
;	       	2 Jan 97	MHG		message                                                             ;
;                                                                                                                   ;
;                                                                                                                   ;
;-------------------------------------------------------------------------------------------------------------------;
DMA_CMD_REG 	=  008h
DMA_MASK_REG  	=  00Ah
DMA_MODE_REG	=  00Bh
DMA_FLIP_FLOP 	=  00Ch
DMA_DISABLE	=  00Dh
DMA_MASK_CLR	=  00Eh
DMA_MEM_START	= 2
DMA_PAGE_SELECT	= 083h
DMA_COUNT	= 3

.386

inportb		macro 	PORT
		mov	dx,PORT
		in	al,dx
		endm

xinportb    	macro 	PORT
		mov	dx,bp
		add	dx,PORT
		in	al,dx
		endm

outportb  	macro 	PORT,VAL
		mov	al,VAL
		mov	dx,PORT
		out	dx,al
		jmp 	$+2
		jmp	$+2
		endm

dspwrite  	macro 	VAL
		local	@@lp

@@lp:		jmp $+2
		mov	dx,022Ch
		in	al,dx
		test	al,080h
		jnz	@@lp

		mov	al,VAL
		out	dx,al
		endm

xdspwrite  	macro 	VAL
		local	@@lp

@@lp:		jmp $+2
		mov	dx,bp
		add	dx,0Ch
		in	al,dx
		test	al,080h
		jnz	@@lp

		mov	al,VAL
		out	dx,al
		endm




;/*******************************************************************************************
;
;
;		SB Real Mode Interrupt routine
;
;		260 		dac flip flop
;		261  		page index
;               262;263         buffer offset       (tail)
;               264;265     	buffer offset       (head)
;               266,267	      	SB address
;               268             Counter
;
;*******************************************************************************************/

TAIL_L          = 264
TAIL_H          = 265

HEAD_L          = 262
HEAD_H          = 263

_TEXT16        	SEGMENT BYTE PUBLIC USE16 'CODE'
  	       	ASSUME  cs:_TEXT16

		PUBLIC  rm_sb_


rm_sb_:   	push	ds
		push    es
    		push    ax
		push	bx
		push	cx
		push	dx
		push	bp
		push   	si
		push	di

		cli				;stop any interrupts
		cld

                mov     ax,0
		mov	es,ax
		mov	si,034h*4
		mov	ax,es:[si]
		mov   	bx,es:[si+2]
	     rept	12
		sal	ax,1
		rcl	bx,1
	     endm
		mov	es,bx
		rol	ax,4
		mov	si,ax     		       ;;//get address

                inc     byte ptr es:[268+si]           ;;counter


		mov	bp,es:[si+266];

    		xinportb 00Eh    		;clear sb dsp

     		mov 	al,020h
     	 	out 	020h,al			;int control port

		mov	bx,es:[HEAD_L+si]
		mov	ax,es:[TAIL_L+si]
		sub	ax,bx  		           ;tail >head
		cmp	ax,256
		jl  	@@not_ready_yet


		;
                ;       move new memory into dma buffer
		;

		push	si
		push	es

                mov     al,es:[si+261]          ;DMA 64K page index
		mov	ah,0
		sal	ax,12
		mov	es,ax			;es now points to dma buffer
                add     ax,01000h               ;64K onwards
		mov	ds,ax

		mov	si,0
                mov     ch,GAP                  ;copy from storage buffer into play buffer
		mov	cl,0
@@lp22:		mov	al,es:[bx]
		mov	ds:[si],al
		inc	si
		inc	bx
		loop	@@lp22

                pop     es
		pop	si

@@cco:
		mov es:[HEAD_L+si],bx
@@miss:

                xdspwrite 014h                  ;;Start dma again

                xdspwrite 0ffh                  ;;DMA 256 bytes to the sound blaster !!
	      	xdspwrite GAP-1

		pop	di
	   	pop	si
		pop	bp
		pop	dx
		pop	cx
		pop	bx
		pop     ax
   		pop	es
		pop	ds
   		iret



@@not_ready_yet:

    		mov	byte ptr es:[268+si],1

	        mov     bx,es:[HEAD_L+si]       ;get pointer to 64K sample buffer
                sub     bx,es:[TAIL_L+si]       ;subtract
		neg	bx
		jz   	@@nogood

	        mov	dx,bx
		sal	dx,8
		mov	di,0
	        mov     bx,es:[HEAD_L+si]       ;get pointer to 64K sample buffer

		push 	si
		push 	es

	        mov     al,es:[si+261]          ;DMA 64K page index
		mov	ah,0
		sal	ax,12
		mov	es,ax			;es now points to dma buffer
                add     ax,01000h               ;64K onwards
		mov	ds,ax


	     	mov	si,0
                mov     ch,GAP                  ;copy from storage buffer into play buffer
		mov	cl,0
@@lp212: 	mov	al,es:[bx]       	;source buffer
		mov	ds:[si],al
		add	di,dx
		adc	bx,0
		inc	si
		loop	@@lp212
		pop  	es
		pop  	si
	        mov  	es:[HEAD_L+si],bx
@@nogood:
                xdspwrite 014h                  ;;Start dma again
                xdspwrite 255                  ;;DMA 256 bytes to the sound blaster !!
	      	xdspwrite 0

		pop	di
	   	pop	si
		pop	bp
		pop	dx
		pop	cx
		pop	bx
		pop     ax
   		pop	es
		pop	ds
   		iret


_TEXT16 	ENDS

	       	END




