	title	LUT.ASM

;---------------------------------------------------------------------------
; This program demonstrates the way to program the DAC for 24-bit LUT on
; the Hercules Graphics Station Card.  We will access the hardware directly
; without going through TIGA.  And we will do everything from the host side
; without using any TI 34010 instruction.
;
; Since we want to be able to access the DAC from the host side, the first
; thing is to set the card to VGA (non-TIGA) mode.  After that, the program
; loads a palette, emulating the 16 colors of EGA, to 16 DAC entries starting
; at location 80h.  The card is then set to 512x480x24 mode bypassing LUT.
; A test pattern of 16 bands, 30 scanlines high each, is then loaded onto
; 34010 video memory.  The display will turn all grey, showing the pattern 
; without going through LUT.  Next we turn the LUT on, now the full 16 colors
; can be seen.
;
; Jiing Shan Lin
; 6/26/90
;---------------------------------------------------------------------------

HSEG	equ	0C000h	; Host I/O Segment
HADDH	equ	07F00h  ; Address high word
HADDL   equ	07E00h  ; Address low word
HCTRL	equ	07D00h  ; Host control register
HDATA	equ	07000h  ; Host data register

code	segment
	assume cs:code, ds:code

	org	100h
start:
	jmp	main

test_pal	label	byte	      	;palette for 16 EGA colors
		db	000h,000h,000h
		db	000h,000h,0A8h
		db	000h,0A8h,000h
		db	000h,0A8h,0A8h
		db	0A8h,000h,000h
		db	0A8h,000h,0A8h
		db	0A8h,054h,060h
		db	0A8h,0A8h,0A8h
		db	054h,054h,054h
		db	054h,054h,0FCh
		db	054h,0FCh,054h
		db	054h,0FCh,0FCh
		db	0FCh,054h,054h
		db	0FCh,054h,0FCh
		db	0FCh,0FCh,054h
		db	0FCh,0FCh,0FCh

m512x480    	label	word
		dw	08	;HESYNC - Horizontal parameters
		dw	12	;HEBLNK
		dw	76	;HSBLNK
		dw	78	;HTOTAL

		dw	01	;VESYNC - Vertical parameters
		dw	35	;VEBLNK
		dw	515	;VSBLNK
		dw	527	;VTOTAL

		dw	0f040h	;DPYCTL - Control regs
		dw	0fffch	;DPSTRT
		dw      0000	;DPYTAP - horizontal start address

		dw	01h	;CONFIG1 clock select register
		dw	0Dh	;CONFIG2 pixel size register
		dw	17H	;DAC COMMAND, bypass lut

main:
	call	set_vga		;set TI to VGA mode

	mov	ax,offset test_pal
	push	ax		;address of test palette
	mov	ax,80h
	push	ax		;start loading from dac 80h
	mov	ax,16
	push	ax		;16 dac entries to load
	call	set_pal		;set palette

	mov	si,offset m512x480
	call	set_mode	;set 512x480x24 video mode

	call	write_pattern	;write test pattern on the TI screen
	xor	ah,ah
	int	16h		;wait for keystroke

	call	enable_LUT
	xor	ah,ah
	int	16h		;wait for keystroke

	call	set_vga		;set TI to VGA mode
	mov	ax,3
	int	10h		

	mov	ax,4C00h
	int	21h		

;---------------------------------------------------------------------------
; set_mode
;	ds:si = pointer to video parameter table
;	ax = bypass/pesudo-color
;---------------------------------------------------------------------------
set_mode	proc	near

	mov	ax,HSEG		;get TI seg address
	mov	es,ax		;into ES
	mov	di,HCTRL	;HSTCTL address
	mov	ax,0d800h	;HALT 34010, auto inc, LBL
	mov	es:[di],ax	;write to 34010

	mov	ax,0000h	;HADDRL value - HESYNC reg
	mov	es:[HADDL],ax	;write ti 34010
	mov	ax,0C000H	;HADDH value - I/O Register seg
	mov	es:[HADDH],ax	;write to 34010

	mov	di,HDATA	;data reg address
	mov	cx,10		;number of consecutive registers
	rep	movsw		;copy the timing values into the 34010
	
	mov	ax,01B0h	;dpytap address
	mov	es:[HADDL],ax	;write to 34010
	mov	ax,0C000h	;seg address
	mov	es:[HADDH],ax	;write to 34010
	movsw			;copy the DPYTAP value

	mov	ax,0C000h	;34010 control word - no auto inc
	mov	es:[HCTRL],ax

	mov 	ax,00C0h	;clock sel / rs2 write address - addrl value
	mov	es:[HADDL],ax	;write to 34010
	mov	ax,0600h	;addrh value
	mov	es:[HADDH],ax	;to 34010
	lodsw			;get clk_sel value
	mov	bx,ax		;save for later
	or	ax,00001000b	;set rs2 = 1
	mov	es:[HDATA],ax

	mov 	ax,00E0h	;pxsize/syncp write address - addrl value
	mov	es:[HADDL],ax	;write to 34010
	mov	ax,0600h	;addrh value
	mov	es:[HADDH],ax	;pix size/syncp address completed
	lodsw			;get value
	mov	es:[HDATA],ax	;write to the register

	mov 	ax,0020h	;command reg address
	mov	es:[HADDL],ax
	mov	ax,0600h
	mov	es:[HADDH],ax
	lodsw			;read value into AX
	mov	es:[HDATA],ax	;write it to the DAC

	mov 	ax,00C0h	;point to the clock reg again
	mov	es:[HADDL],ax
	mov	ax,0600h
	mov	es:[HADDH],ax
	mov	ax,bx		;get clock sel value back
	and	ax,11110111b	;mask out RS2 bit
	mov	es:[HDATA],ax	;write to the clock_sel/rs2 port

	mov	ax,0000h     	;reset address pointers
	mov	es:[HADDL],ax
	mov	es:[HADDH],ax

	ret			;done.

set_mode	endp

;---------------------------------------------------------------------------
; enable_LUT
;---------------------------------------------------------------------------
enable_LUT	proc	near

	mov	ax,HSEG		;get TI seg address
	mov	es,ax		;into ES

	mov 	ax,01C0h	;clock sel / rs2 read address
	mov	es:[HADDL],ax	;write to 34010
	mov	ax,0600h	;addrh value
	mov	es:[HADDH],ax	;to 34010
	mov	ax,es:[HDATA]	;fecth current value
	mov	bx,ax		;save for later

	mov 	ax,00C0h	;clock sel / rs2 write address
	mov	es:[HADDL],ax	;write to 34010
	mov	ax,0600h	;addrh value
	mov	es:[HADDH],ax	;to 34010
	mov	ax,bx		;get saved value
	or	ax,00001000b	;set rs2 = 1
	mov	es:[HDATA],ax
	
	mov 	ax,0020h	;command reg address
	mov	es:[HADDL],ax
	mov	ax,0600h
	mov	es:[HADDH],ax
	mov	ax,13h		;enable LUT mode
	mov	es:[HDATA],ax	;write it to the DAC

	mov 	ax,00C0h	;point to the clock reg again
	mov	es:[HADDL],ax
	mov	ax,0600h
	mov	es:[HADDH],ax
	mov	ax,bx		;get clock sel value back
	and	ax,11110111b	;reset RS2 bit
	mov	es:[HDATA],ax	;write to the clock_sel/rs2 port

	ret

enable_LUT	endp
;---------------------------------------------------------------------------
clk_sel	equ	02h
pxsize	equ	00h
syncp	equ	0Ch
dac_cmd	equ	01001011b	

;---------------------------------------------------------------------------
; set_vga
;---------------------------------------------------------------------------
set_vga		proc	near

	mov	ax,HSEG
	mov	es,ax
	mov	di,HCTRL
	mov	ax,0d800h
	mov	es:[di],ax

	mov 	ax,00E0h
	mov	es:[HADDL],ax
	mov	ax,0600h
	mov	es:[HADDH],ax
	mov	ax,pxsize
	or	ax,syncp
	mov	es:[HDATA],ax

	mov 	ax,00C0h
	mov	es:[HADDL],ax
	mov	ax,0600h
	mov	es:[HADDH],ax
	mov	ax,clk_sel
	or	ax,00001000b	
	mov	es:[HDATA],ax

	mov	dx,3C6h
	mov	ax,dac_cmd	
	out	dx,al		

	mov 	ax,00C0h
	mov	es:[HADDL],ax
	mov	ax,0600h
	mov	es:[HADDH],ax
	mov	ax,clk_sel
	mov	es:[HDATA],ax

	mov	ax,0000h
	mov	es:[HADDL],ax
	mov	es:[HADDH],ax

	ret

set_vga	endp

;---------------------------------------------------------------------------
; write_pattern
;	write a test pattern onto TI's video ram
;---------------------------------------------------------------------------
write_pattern	proc	near

	mov	ax,HSEG
	mov	es,ax		;point ES at TI seg
	mov	ax,0D800h	;34010 control word
	mov	es:[HCTRL],ax
	mov	ax,0000h	;screen buffer start address - low
	mov	es:[HADDL],ax	
	mov	ax,0000h	;screen buffer start address - high
	mov	es:[HADDH],ax	

	mov	dx,46E8h	;disable VGA 
	mov	ax,06h
	out	dx,ax

	mov	ax,0A000h	;16 bit seg address when VGA is disabled
	mov	es,ax		;
	xor	di,di		;HDATA address
	mov	cx,16		;16 bands of increasing grey scale
	xor	ax,ax		;start from color 0
	mov	ax,8080h
next_band:
	push	cx		;save
	mov	cx,512 * 30 * 2	;x-width * scans-per-band * words-per-pixel
rep	stosw
	add	ax,0101h	;next color
	pop	cx		;bands to go
	loop	next_band

	mov	dx,46E8h	;enable VGA 
	mov	ax,0eh
	out	dx,ax

	ret

write_pattern	endp
;---------------------------------------------------------------------------
; set_pal
;	set a block of palette entries
;	typedef struct {
;		char r;
;		char g;
;		char b;
;	} PALET;
; 	set_pal(short count, short index, PALET *palet)
;---------------------------------------------------------------------------
set_pal	proc	near

	push	bp
	mov	bp,sp

	mov	ax,HSEG		;get TI seg address
	mov	es,ax		;into ES

	mov 	ax,01C0h	;read config 1 register
	mov	es:[HADDL],ax
	mov	ax,0600h
	mov	es:[HADDH],ax
	mov	ax,es:[HDATA]	;fetch config 1
	mov	bx,ax		;save  value

	mov 	ax,00C0h	;write config 1 register
	mov	es:[HADDL],ax
	mov	ax,0600h
	mov	es:[HADDH],ax
	mov	ax,bx		;get saved value
	or	ax,00001000b	;set RS2 bit
	mov	es:[HDATA],ax	;write it out

	mov	dx,3C6h		;command register
	mov	al,13h		;enable, 24-bit w/ look up, 24-bit LUT entry
	out	dx,al		

	mov 	ax,00C0h	;write config 1 register
	mov	es:[HADDL],ax
	mov	ax,0600h
	mov	es:[HADDH],ax
	mov	ax,bx		;fetch saved  value
	and	ax,11110111b	;reset RS2 bit
	mov	es:[HDATA],ax	;write it out

dacwrite:
;----- select RAM write mode address reg, set starting palette index 

	mov	ax,[bp+6]	;get starting palette index (index)
	mov	dx,03C8h	;write mode address register
	out	dx,al		;set write mode address reg 

	mov	cx,[bp+4]	;no. of palette entries to set (count)
	mov	si,[bp+8]	;ds:si -> palettes
	mov	dx,03C9h	;look up table data register
dac_lp1:
	lodsb			;fetch RED
	out	dx,al		;write to palette
	lodsb			;fetch GREEN
	out	dx,al		;write to palette
	lodsb			;fetch BLUE
	out	dx,al		;write to palette
	loop	dac_lp1

	pop	bp
	ret

set_pal	endp

code	ends
	end	start

