;SQR_T.ASM          10-14-83
;
;PROGRAM TO TAKE KEYBOARD INPUT AND CALCULATE THE SQUARE
;ROOT USING THE SQ ROOT ROUTINE, THEN DISPLAY THE RESULT
;
EXTRN ASCII_BIN:FAR    ;EXTERNAL SUBROUTINE
EXTRN BIN_ASCII:FAR    ;EXTERNAL SUBROUTINE
EXTRN DEC_ADJ:FAR      ;EXTERNAL SUBROUTINE
EXTRN PUT_DEC:FAR
;---------------------------------------
STACK SEGMENT PARA STACK 'STACK'
      DB 256 DUP(0)
STACK ENDS
;----------------------------------------
DATA SEGMENT PARA 'DATA'
ESC           EQU  27  ;ESC USED TO RETURN TO DOS
END_SYM       EQU '\' ;SYMBOL AT END OF STRING
SC_TITLE      DB  'INTEGER SQUARE ROOT ROUTINE\'
TYPE_NUM      DB  'FOR A POSITIVE NUMBER FROM 0 TO 32767\'
INPUT_NUM     DB  'INPUT TEST NUMBER \'
COL_HEADER    DB  'TEST NUMBER            SQ ROOT\'
UNDERLINE     DB  '-----------            --------\'
ERR_MSG1      DB  'NOT VALID NUMBER - REDO \'
ERR_MSG2      DB  'NUMBER TOO LARGE - REDO \'
ERR_MSG3      DB  'NEGATIVE NUMBER - REDO\'
BLANKS        DB  '                         \'  ;25 BLANKS
TEST_STRING   DB  10 DUP(0)
TEST_NUMBER   DW  0  ;THE TEST_STRING CONVERTED TO A NUMBER
CHAR_COUNT    DW  0  ;NO. OF CHARS IN A STRING - CX IN BIOS CALL
SQ_ROOT_VALUE   DW  0  ;CALUCLATED SQ ROOT VALUE
SQ_ROOT_STRING  DB '          \' ;STRING TO PUT CAL VALUE IN FOR DISP
OFFSET_VALUE  DW  0
INPUT_LARGE   DW  0  ;STATUS PASSING INDICATOR
INPUT_STATUS  DW  0  ;STATUS PASSING INDICATOR
DEC_POINT     DW  0
test1         db  'test4\'
test2         db  'test2\'
test3         db  'test3\'
TEST_NUM_CNT  DB  10 DUP (0)   ;STRING TO USE IN FINDING WHERE DECIMAL WAS
TEST_NUMBER_SIZE  DW  0        ;INDICATOR IF TEST_NUMBER <1 OR >1
data ends
;----------------------------------------
CODE  SEGMENT PARA PUBLIC 'CODE'
START PROC FAR
;
;STANDARD PROGRAM PROLOGUE
;
       ASSUME CS:CODE                  

       PUSH DS
       MOV  AX,0
       PUSH AX
       MOV  AX,DATA
       MOV  DS,AX
       ASSUME DS:DATA

       CALL CLEAR_THE_SCREEN 
 ;PUT STRING OF SCREEN

;IF COLOR GRAPHICS MAKE SURE IS MODE 2
        MOV  AH,15
        INT  10H
        CMP  AL,7           ;IS IT MONOCHROME?
        JE  SCREEN_MODE_OK  ;YES
        CMP  AL,2           ;NOT MONO, IS MODE 2?
        JE  SCREEN_MODE_OK  ;YES
        MOV  AH,0           ;NOT MODE 2 SO MAKE IT
        MOV  AL,2           ;   MODE 2
        INT  10H
SCREEN_MODE_OK:

;SC_TITLE
       MOV AH,2         ;CALL TO SET CURSOR POSITION
       MOV  DX,0112H    ;CURSOR POSITION
       MOV  BH,0
       INT  10H
       MOV  BX,OFFSET SC_TITLE  ;PUT SC_TITLE ADDRESS IN BX
       MOV  OFFSET_VALUE,BX     ;PUT ADDRESS IN VARIABLE
       CALL DISPLAY  

;TYPE_NUM
      MOV  AH,2
      MOV  DX,0210H     ;CURSOR POSITION
      MOV  BH,0
      INT  10H
      MOV  BX,OFFSET TYPE_NUM
      MOV  OFFSET_VALUE,BX      ;PUT ADDRESS IN VARIABLE
      CALL DISPLAY

;INPUT_NUM
       MOV  AH,2
       MOV  DX,0310H    ;CURSOR POSITION
       MOV  BH,0
       INT  10H
       MOV  BX,OFFSET INPUT_NUM
       MOV  OFFSET_VALUE,BX
       CALL DISPLAY

;COL_HEADER
       MOV  AH,2        ;CALL TO SET CURSOR POSITION
       MOV  DX,0510H    ;CURSOR POSITION
       MOV  BH,0
       INT  10H
       MOV  BX, OFFSET COL_HEADER
       MOV  OFFSET_VALUE,BX        ;PUT ADDRESS IN VARIABLE
       CALL DISPLAY

;UNDERLINE
       MOV  AH,2
       MOV  DX,0610H     ;CURSOR POSITION
       MOV  BH,0
       INT  10H
       MOV  BX,OFFSET UNDERLINE
       MOV  OFFSET_VALUE,BX
       CALL DISPLAY

;POSITION CURSOR FOR KEYBOARD INPUT
INPUT:
;CLEAR_INPUT_AREA
       MOV  AH,2
       MOV  DH,3
       MOV  DL,25H
       MOV  BH,0
       INT  10H
      
      MOV   BH,0
       MOV  CX,30    ;blank 30 spaces       
       MOV  AH,10    ;WRITE CHAR AT CURSOR LOCATION
       MOV  AL,' '   ;BLANK
       INT  10H

;clear test_string
       LEA  SI,TEST_STRING
       mov   cx,10             ;TEST STRING IS 10 CHAR LONG
next_char:
        MOV  BYTE PTR [SI],' '
        inc  SI
        dec  cx
        cmp  cx,0
        JA  next_char

;SCROLL PART OF SCREEN DOWN TOO BET READY FOR NEXT INPUT
       MOV  AH,7     ;SCROLL ACTIVE PAGE DOWN
       MOV  AL,1     ;NUMBER OF LINES
       MOV  CH,7     ;UPPER LINE TO SCROLL
       MOV  CL,0     ;LEFT COLUMN OF SCROLL
       MOV  DH,23    ;LOWER LINE OF SCROLL
       MOV  DL,79    ;RIGHT COLUMN OF SCROLL
       MOV  BH,0FH   ;ATTRIBUTE OF BLANK LINE
       INT  10H      ;DO IT

       MOV  INPUT_LARGE,0   ;SET TO ZERO AT START-UNDER 65384
       MOV  INPUT_STATUS,0  ;SET TO ZERO AT START-NUMBERS
       MOV  AH,2
       MOV  DX,0325H      ;CURSOR POSITION
       MOV  BH,0
       INT  10H

       CALL READ_KEYS

;PUT THE TEST_NUMBER UNDER THE TEST NUMBER COLUMN HEADING
       MOV  AH,2
       MOV  DX,0711H        ;CURSOR POSITION
       MOV  BH,0
       INT  10H
       MOV  BX,OFFSET TEST_STRING
       MOV  CX,10
PUT_TEST_NUMBER:
       MOV  AL,[BX]         ;PUT STRING CHAR IN AX
       MOV  AH,14           ;FUNCTION CODE FOR WRITE AND ADVANCE CURSOR
       INT  10H
       INC  BX              ;NEXT CHARACTER IN STRING
       LOOP PUT_TEST_NUMBER ;PUT ALL OF STRING + BLANKS



;PREPAIR TO CALL ASCII_BIN ROUTINE
;PUT STARTING ADDRESS OF STRING IN BX
;PUT CHARACTER COUNT IN CX
       MOV  BX,OFFSET TEST_STRING
       MOV  CX,CHAR_COUNT

       CALL ASCII_BIN       ;CONVERT STRING TO NUMBER


      JC  CARRY_SET        ;GO CHECK WHY
      MOV TEST_NUMBER,AX   ;SAVE TEST NUMBER
      MOV  DEC_POINT,DX    ;SAVE DECIMAL POINT
      CMP AX,0             ;CHECK FOR NEGATIVE
      JGE  NUM_OK          ;NUMBER IS GOOD-GO DO SQ ROOT  
      MOV AH,2
      MOV  DX,0730H        ;CURSOR POSITION
      INT  10H
      MOV  BX,OFFSET ERR_MSG3   ;NEGITIVE NUMBER
      MOV  OFFSET_VALUE,BX
      CALL DISPLAY

      JMP  INPUT            ;NEXT KEYBOARD INPUT

BAD_CHAR:
      MOV  AH,2
      MOV  DX,0730H         ;CURSOR POSITION
      MOV  BH,0
      INT  10H
      MOV  BX,OFFSET ERR_MSG1  ;NOT VALID INPUT
      MOV  OFFSET_VALUE,BX
      CALL DISPLAY

      JMP  INPUT           ;GO GET NEXT KEYBOARD INPUT

CARRY_SET:
      cmp  di,0ffh          ;check for bad character
      jne  bad_char

       MOV  AH,2
       MOV  DX,0730H        ;CURSOR POSITION
       MOV  BH,0
       INT  10H
       MOV  BX,OFFSET ERR_MSG2
       MOV  OFFSET_VALUE,BX
       CALL DISPLAY

       JMP  INPUT           ;NOT VALID, GO GET NEW INPUT

NUM_OK:

;ADJUST NUMBER FOR SQUART ROOT ROUTING BY MAKING NUMBER AS LARGE AS 
;POSSIBLE, BUT LESS THEN 32768, BY MULTIPLYING BY 10 AND CHANGINE
;DECIMAL POINT TO MATCH.                                                       
; CALL DEC_ADJ  WITH AX = NUMBER - 16 BIT SIGNED                    
;                    CX = NUMBER OF CHARACTERS TO RIGHT OF DECIMAL POINT
;RETURN WITH AX = NUMBER AND   CX = NUMBER OF CHARACTERS TO RIGHT
;OF DECIMAL POINT THAT TOGETHER = OLD NUMBER
; NOTE CX WILL BE A EVEN NUMBER
   
 
       MOV AX,TEST_NUMBER
       MOV CX,DEC_POINT
       CALL DEC_ADJ     
  
       MOV  TEST_NUMBER,AX
      
;NOW READY TO CALCULATE SQUARE ROOT.  AX IS TO CONTAIN THE TEST
;NUMBER WHEN THE SQ_ROOT ROUTINE IS CALLED AND AX WILL CONTAIN
;THE CALCULATED SQ ROOT ON RET.

        MOV AX,CX         ;PUT DEC POINT IN AX FOR DIVIDE
        CWD
        MOV BX,2
        DIV BX
        MOV  DEC_POINT,AX  ;STORE SQ ROOT OF DEC POINT


 
       MOV  AX,TEST_NUMBER    ;PUT NUMBER IN AX
       CALL SQ_ROOT
       MOV  SQ_ROOT_VALUE,AX  ;SAVE THE CALCULATED SQ ROOT VALUE


;CONVERT THE SQ_ROOT VALUE TO ASCII STRING AND PUT UNDER THE
;SQ ROOT HEADING                            

;CONVERT THE NUMBER TO A ASCII STRING

       MOV  BX,OFFSET SQ_ROOT_STRING      ;PLACE TO PUT RESULT
       CALL BIN_ASCII

;ON RETURN BX HOLDS ADDRESS OF THE STRING AND CX THE COUNT

;POSITION DECIMAL POINT IN SQ ROOT STRING
; CALL   PUT_DEC  WITH
;    AX = 10  SIZE OF STRING 
;    BX = OFFSET OF ASCII STRING
;    CX = NUMBER OF CHARACTERS IN STRING
;    DX = NUMBER OF CHARACTERS TO RIGHT OF DECIMAL
;RETURN IS WITH DECIMAL IN STRING AT BX

       MOV  AX,10
       MOV  DX,DEC_POINT
       CALL PUT_DEC

;SQ_ROOT_STRING NOW CONTAINS THE ANSWER READY FOR DISPLAY

       MOV  AH,2
       MOV  DX,0728H       ;CURSOR POSITION
       MOV  BH,0
       INT  10H

       MOV  BX,OFFSET SQ_ROOT_STRING
       MOV  OFFSET_VALUE,BX
       CALL DISPLAY

       JMP INPUT            ;READY FOR AN OTHER KEYBOARD INPUT

START ENDP
;------------------------------------------
CLEAR_THE_SCREEN  PROC NEAR
       PUSH AX
       PUSH BX
       PUSH CX
       PUSH DX

       STI             ;ENABLE INTERRUPTS
       MOV  AH,0       ;SELECT 80X25, B/W, ALPHANUMERIC
       INT  10H  
       MOV  AH,6       ;CLEAR THE SCREEN WITH THE SCROLL
       MOV  AL,0       ;   UP OPTION
       MOV  CX,0                                       
       MOV  DH,24                       
       MOV  DL,79                                      
       MOV  BH,7                                           
       INT  10H  
            
       POP DX
       POP CX
       POP BX
       POP AX
       RET             ;RETURN TO CALLER
CLEAR_THE_SCREEN ENDP
;------------------------------------------
DISPLAY PROC NEAR
;GET THE CHARACTER COUNT
       MOV  CHAR_COUNT,0      ;SET TO 0 FOR THIS STRING
       MOV  BX,OFFSET_VALUE   ;GET OFFSET OF STRING IN BX
       XOR  AX,AX
LOOP_COUNT:
       MOV  AL,[BX]    ;PUT STRING CHAR IN AL
       CMP  AL,END_SYM  ;IS THIS LAST SYMBOL IN STRING?
       JE   DISP1      
       INC  BX             ;ADDRESS OF NEXT CHARACTER IN STRING
       ADD  CHAR_COUNT,1   ;COUNT OF CHARACTERS IN STRING
       JMP  LOOP_COUNT     ;DO UNTIL END_SYM ENCOUNTERED

;PUT THE STRING ON THE SCREEN
DISP1:  MOV  BX,OFFSET_VALUE     ;GET OFFSET OF STRING IN BX
        MOV  CX,CHAR_COUNT   ;NO. OF CHARACTERS IN STRING
DISP2:  MOV  AL,[BX]         ;GET NEXT CHARACTER 
        CALL DISPCHAR
        INC  BX              ;POINT TO NEXT CHARACTER
        LOOP DISP2           ;DO IT CX TIMES

        RET
DISPLAY ENDP
;---------------------------------------------------------
DISPCHAR PROC NEAR
        PUSH BX
        MOV  BX,0     ;SELECT DISPLAY PAGE 0
        MOV  AH,14    ;FUNCTION CODE FOR 'WRITE'
        INT  10H      ;CALL BIOS
        POP  BX
        RET
DISPCHAR ENDP
;--------------------------------------------------------
READ_KEYS PROC NEAR
       PUSH AX
       PUSH DI
       STI            ;ENABLE INTERRUPTS
       MOV  AH,15     ;READ DISPLAY PAGE NUMBER INTO BX
       INT  10H
       MOV  DI,0      ;SET KEY COUNT TO ZERO
       MOV  CX,5      ;UP TO 5  KEY STROKES
GET_KEY:
       MOV  AH,0      ;READ NEXT KEY
       
       INT 16H
       CMP  AL,ESC    ;IS IT ESC?
       JE   GO_EXIT   ;RETURN TO DOS IN TWO STEPS(JE SHORT-LABEL ONLY)
       CMP  AL,0DH    ;IS IT A CARRIAGE RETURN?
       JE   SAVE_CNT  ;IF IT WAS A CARRIAGE RETURN THEN GO TO NEXT STEP
       MOV  TEST_STRING[DI],AL    ;STORE THE KEY INPUT
       INC  DI                    ;INCREASE THE KEY COUNT
       MOV  AH,14                 ;DISPLAY THE CHARACTER
       PUSH DI                     ;SAVE REGISTER
       INT  10H
       POP  DI
       LOOP GET_KEY               ;GO GET NEXT KEY
SAVE_CNT:
       MOV  CX,DI                 ;PUT FINAL KEY COUNT IN CX
       MOV  CHAR_COUNT,CX         ;STORE NO OF CHARS IN STRING
       LEA  BX,TEST_STRING        ;BUFFER ADDRESS IN BX
       POP DI
       POP AX
       RET               ;RETURN TO CALLER
GO_EXIT:
       POP DI
       POP AX
       POP AX
       JMP EXIT          ;RETURN TO DOS

READ_KEYS ENDP
;----------------------------------------------------------
;-----------------------------------------------------------------
;
;-------------------------------------------------------------
;----------------------------------------------------------------
;INTEGER SQUARE ROOT
;  CALL WITH    AX = ARGUMENT
;  RETURN       AX = SQUARE ROOT
;
SQ_ROOT PROC
SQRT:
        PUSH BX
        PUSH CX
        PUSH DX
        MOV  DX,AX     ;ARGUMENT INTO DX
        MOV  CX,8      ;NUMBER OF ITERATIONS
        XOR  BX,BX     ;CLEAR THE REMAINDER
        MOV  AX,BX     ;CLEAR TRIAL VALUE AND FINAL RESULT STORE

SQRT1:
        SHL  BX,1      ;DOUBLE PARTIAL RESULT
        INC  BX        ;GUESS NEXT BIT IS A 1
        SHL  DX,1      ;FETCH 2 NEW BITS
        RCL  AX,1      ; FROM ARGUMENT
        SHL  DX,1
        RCL  AX,1
        SUB  AX,BX     ;DO A TRIAL SUBTRACTION
        JNC  SQRT2     ;GUESS WAS RIGHT
                       ; APPEND A 1 BIT
        ADD  AX,BX     ;GUESS WAS WRONG, PUT IT BACK
        DEC  BX        ;AND CLEAN UP FOR NEXT PASS
        LOOP SQRT1
        JMP  SQRT3     ;GO SCALE RESULT
SQRT2: 
        INC  BX        ;CONVERT xxxx01 to
                       ;xxxx10, i.e. append a 1 bit
        loop sqrt1
SQRT3:
        SAR  BX,1      ;DIVIDE BY 2 TO GET
                       ;ACTUAL SQUARE ROOT
        MOV  AX,BX     ;RETURN RESULT IN AX

        POP  DX
        POP  CX
        POP  BX
        
        RET            ;RETURN TO CALLER

SQ_ROOT ENDP
;--------------------------------------------------------------------
EXIT_TO_DOS PROC FAR
EXIT:  RET            ;RETURN TO DOS
EXIT_TO_DOS ENDP
;----------------------------------------------------------

CODE   ENDS
       END   START
_^ZY[XϋWVRQSP^ 6CCX]]ҊFPA ^;~ Z P