


;		    TURBO PASCAL CALLABLE
;	       AT&T 640*400 POINT SETTING ROUTINE
;
;Author: Rob Alexander
;	 13217 Emily Lane
;	 Dallas,Tx 75240
;	 214-644-9359
;
;Comments:  I have heavily documented what I have learned about	the
;	    AT&T 6300 640*400 graphics and handling the	Turbo Pascal
;	    assembly language "interface"; parameter passing etc...
;	    I did this primarily as a reference	for future work	so
;	    I wouldn't have to fight the same battle twice. I hope
;	    others may benefit also.
;
;**********************	STACK MEMORY MAP **************************
;
; PROCEDURE Point( X,Y:INTEGER;VAR Test: INTEGER) sets up the stack as
; follows
;  < Top of Stack before Call		>		    {Increasing	addr}
;  < X value		       (2 bytes)>  {SP+8}    {BP+10}	^
;  < Y value		       (2 bytes)>  {SP+6}    {BP+8}	*
;  < Test value	Segment	addr   (2 bytes)>			*
;  < Test value	Offset	addr   (2 bytes)>  {SP+2}    {BP+4}	*
;  < Return Address	       (2 bytes)>  {SP}	     {BP+2}	*
;  < BP	register	       (2 bytes)>  {SP-2}    {BP}	*
;
;*********************************************************************
;
; Define Point Procedure
;
; CONSTANTS DEFINITION
;
    GraphSeg = 0B800H		   ;Graphics Memory Segment Address
;
CODE   SEGMENT
       Assume CS:Code
;
Point  PROC  NEAR
       push  bp			     ;Save Base	pointer
       mov bp,sp		     ;Initialize Base pointer
;      les di,[bp+4]		     ;For test value passing
;****************** 8k BLOCK CALCULATION*****************************
;
;DISCUSSION: In	640 by 400 mode, the 32K graphics memory is divided into
;	  four 8000 byte long blocks. Each block contains the pixel
;	  definitions for 100 rows. According to the AT&T system programmers
;	  guide, the memory map	looks like:
;
;     ----------------	  B800:7F3F
;    * Rows	      *
;    * 3,7,11..399    *
;    ------------------	  B800:6000
;    ------------------	  B800:5F3F
;    * Rows	      *
;    * 2,6,10,..398   *
;    ------------------	  B800:4000
;    ------------------	  B800:3F3F
;    * Rows	      *
;    * 1,5,9..397     *
;    ------------------	  B800:2000  {there are	192 unused bytes between
;    ------------------	  B800:1F3F   blocks}
;    * Rows	      *
;    * 0,4,8,..396    *
;    ------------------	  B800:0000
;
;
; CALCULATION METHOD:
;
;  1) Read Y (row number) passed from Turbo Pascal
;  2) Determine	remainder of Y/4. This is accomplished by masking upper	14
;     bits of Y	value so that
;      LSB+1   LSB	  Action
;	0	0	 Y value divisible by 4. Pixel in first	8 k block.
;	0	1	 Remainder of 1/4. Pixel in second 8K block
;	1	0	 Remainder of 1/2. Pixel in third 8K block
;	1	1	 Remainder of 3/4. Pixel in fourth 8K block.
;
;  3) Multiply remainder by 2000H to obtain correct 8K page offset
;
;  CONSTANTS DEFINITION
;
     OffsetMult	=  20H		      ;8K offset
     Ymask	=  03H		      ;Row number mask
     OffsetShift = 08		      ;shift count for result of offset	calc.
;
; Algorithm: The offset	calculation is done as
;
;    a)	  ax<----8K_OffsetMult
;    b)	  bx<----Row number
;    c)	  bx<----Row number (AND) Ymask	  {Result is 8K_Block#}
;    d)	  ax<----20H*Remainder	{want result in	AX register}
;    e)	  ax<----20H*256	{Perform shift to obtain proper	bit level
;
;    Perform Calculation
;
	mov ax,OffsetMult	     ;Offset multiplier
	mov bx,[bp+8]		     ;Y	value passed from Turbo
	mov cl,OffsetShift	     ;Load CL register with shift count
	and bl,Ymask		     ;mask off higher order bits
	mul bl			     ;Find Bank	offset
	shl ax,cl		     ;Bring offset to correct bit level
	mov dx,ax		     ;Save 8K_BlockOffset in DX
;
; ************************ Row Block Calculation ***********************
;
; Discussion: According	to Systems Programmer guide, each 8K block contains
;	      the pixel	values for 100 rows as follows;
;
;					 Row Number    Offset
;   /byte 0/byte 1/......./byte	79/	   99	      8K_BlockOffset+99*80
;   /byte 0/byte 1/......./byte	79/	   98	      8K_BlockOffset+98*80
;
;
;   /byte 0/byte 1/......./byte	79/	    1	      8K_BlockOffset+1*80
;   /byte 0/byte 1/......./byte	79/	    0	      8K_Block#+0*80
;
; CALCULATION METHOD:
;
;   1)	Read Y {row number} from stack
;   2)	Row_Block# = Row Number/4
;   3)	Row_Offset=Row_Block# *	80
;   4)	Offset = 8K_Block Offset + Row_Offset
;
; ALGORITHM
;   a)	ax<----	Row_OffsetMult
;   b)	bx<----	Y value	{Row number} passed from Turbo Pascal
;   c)	cl<----	Row_RmdrShift
;   d)	bx<----	Row number/4
;   e)	ax<----	(Row number/4)*80
;   f)	dx<----	8K_BlockOffset + Row_BlockOffset
;
;  CONSTANTS DEFINITION
;
    Row_RmdrShift  = 80
    Row_BlockShift = 2
;
;  Perform Calculation
;
	mov al,Row_RmdrShift		 ;
	mov bx,[BP+8]			 ;Read Y value passed from Turbo Pascal
	mov cl,Row_BlockShift		 ;
	shr bx,cl			 ;Divide Row number by 4
	mul bl				 ;Find Row_Offset
	add dx,ax			 ;Calculate offset
;
;*********************** COLUMN	OFFSET CALCULATION ***********************
;
; Discussion: The pixel	values for each	row {640 pixels} are stored in
;	      80 bytes.	{1 bit per pixel} as shown below
;     /byte 0/byte 1/......./byte n/...../byte 79/
;      ^		      ^
;      |.. Row base address   |..Column	Address/8
;
; CALCULATION METHOD:
;
;   1) Column_byte_Addr=X value/8
;
;  CONSTANTS DEFINITION
;
     Column_Shift = 3
;
;  PERFORM CALCULATION
;
     mov ax,[bp+10]		  ;Read	X value	passed from Turbo Pascal
     mov bx,ax			  ;Save	X value	for next calculation stage
     mov cl,Column_Shift	  ;Initialize Shift count
     shr ax,cl			  ;Divide X value by 8
     add dx,ax			  ;Save	Offset
;
;************************ PIXEL	MASK GENERATION	**************************
;
;  Discussion: Finally,	we're ready to set the pixel. The pixel bit map
;	       looks like
;
;	      /bit 7/ bit 6/......../bit 1/bit 0/
;      pixel 0...^			    ^..pixel 7
;
;	    {the bit map is the	reverse	from what you would expect}
;
;  CALCULATION METHOD
;
;   1) Pixel No<----- Remainder{Column address,8}
;   2) Pixel Mask<---- 1 shifted by pixel number
;   3) Reg <---- Current Pixel Byte
;   4) Updated Pixel Byte<----Pixel Mask (OR) Pixel Settings
;   5) Mem<----- Pixel Byte
;
;   CONSTANTS DEFINITION
;
     Const_ = 128
     Pixel_Rmdr_Mask = 0007
;
;  PERFORM CALCULATION
;
	mov ax,GraphSeg
	mov es,ax
	mov di,dx
	and bl,Pixel_Rmdr_Mask		    ;Find remainder of Col#/8
	mov cl,bl			    ;Generate Pixel Mask
	mov bx,Const_			     ;
	shr bx,cl
	mov al,byte ptr	es:[di]		    ;Read Current Pixel	Setting
	or al,bl			    ;Set pixel
	mov byte ptr es:[di],al
;	mov word ptr es:[di],bx
;
;	restore	registers and return to	Turbo
;
	mov sp,bp
	pop bp
;************************************************************************
;************************************************************************
;************************************************************************
;********* ATTENTION, ATTENTION, ATTENTION, ATTENTION *******************
;********* In order for	External procedure to work,   *******************
;********* you must figure out how many	parameters    *******************
;********* were	passed on stack	{in bytes} and	      *******************
;********* and include that number in return statemt. *******************
;********* In the case of this program;		      *******************
;*********					      *******************
;*********   X co-ordinate value = 2 bytes	      *******************
;*********   Y co-ordinate value = 2 bytes	      *******************
;*********    Test value address = 4 bytes	      *******************
;*********			   -------	      *******************
;*********			   8 bytes	      *******************
;*********					      *******************
;********* It took me a	hell of	a long time to figure *******************
;********* that	out.- Rob Alexander		      *******************
;************************************************************************
;************************************************************************
;************************************************************************
	ret  08H			     ;Release Stack used for Call
Point	ENDP
Code	ENDS
END
