CODE SEGMENT ASSUME CS:CODE, DS:CODE, ES:CODE, SS:CODE ORG 256 MAIN: CALL InitScreen CALL InitRegs MOV AX,3DB0h MOV CX,0101h MOV DX,194Fh CALL PutBox CALL GetKey MOV AX,3DB1h CALL PutBox CALL GetKey MOV AX,3DB2h CALL PutBox CALL GetKey CALL CLS MOV AH,0Ah MOV DH,7 MOV SI,OFFSET TEST2 CALL CENTER CALL GetKey MOV SI,OFFSET TEST2 CALL toUpperCase MOV AH,0Bh MOV DH,8 MOV SI,OFFSET TEST2 CALL CENTER CALL GetKey MOV SI,OFFSET TEST2 CALL toLowerCase MOV AH,0Fh MOV DH,9 MOV SI,OFFSET TEST2 CALL CENTER CALL GetKey CALL ColorPrintMsg CALL ScrollUp CALL GetKey CALL ScrollUp CALL GetKey CALL ScrollUp CALL GetKey CALL CLS MOV AX,"F3" CALL fromHex CALL toHex CALL PrintMsg CALL GetKey CALL CLS CALL PrintBin CALL PrintDec CALL GetKey MOV AL,7Fh CALL toHex MOV DI,OFFSET NUM STOSW CALL PrintMsg CALL GetKey CALL CLS CALL PrintKeyCode CALL dimScreen JMP ExitProgram ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; InitScreen: MOV AX,0003h INT 10h RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Dims the screen by changing every color to dark grey. ; ; Destroys: AL,CX,DI,ES ; dimScreen: MOV DI,0B800h MOV ES,DI XOR DI,DI MOV AL,8 MOV CX,2000 CLD doitAgain95: INC DI STOSB LOOP doitAgain95 RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Draws a square box on the screen. ; ; AH <- color attribute ; AL <- fill character ; CX <- start coordinates for upper left-hand corner (CH=row CL=column) ; DX <- end coordinates for lower right-hand corner (DH=row DL=column) PutBox: CALL SaveRegs PUSH CX SUB DL,CL SUB DH,CH XOR CX,CX MOV CL,DL XOR BX,BX MOV BH,DH POP DX ; Now, horizontal width is in CX ; Vertical height is in BX ; and DX = start coordinates dothisAgain: CALL CalcXY PUSH BX PUSH CX CALL CREP ; CREP destroys: BX,CX,ES,DI POP CX POP BX INC DH CMP DH,BH JB dothisAgain CALL RestoreRegs RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Calculate the character pointer for CPRINT setting ; register DI based on the values of DL and DH. ; ; DL <- column (0 to 79) ; DH <- row (0 to 24) ; DI -> screen memory pointer ; CalcXY: PUSH DX ; Make sure X and Y pointers are not out of bound CMP DL,79 JBE columnOK MOV DL,79 columnOK: CMP DH,24 JBE rowOK MOV DH,24 rowOK: ; Now calculate DI = DL * 2 + DH * 160 XCHG AX,DI SHL DL,001h MOV AL,160 MUL DH XOR DH,DH ADD AX,DX XCHG AX,DI POP DX RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Returns the length of a null-terminated string. ; ; DS:SI <- string pointer ; CX -> string length ; ; Destroys: AL,DI ; StrLen: PUSH AX PUSH DI MOV AL,0h MOV CX,0FFFFh MOV DI,SI CLD StrLen_LOOP: INC CX SCASB JNE StrLen_Loop POP DI POP AX RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Prints a string in the center of a row ; ; AH <- COLOR attribute ; DH <- row ; ES:SI <- null-terminated string to print ; CENTER: PUSH AX CALL StrLen ; Let's hope the string is less than 80 bytes. ; We don't do any error checking here. :P SHR CX,1 MOV DL,40 SUB DL,CL CALL CalcXY POP AX CALL CPRINT RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Moves the cursor on the screen to a location set by ; DL and DH. ; ; DL <- column ; DH <- row ; MoveCursor: XOR BX,BX MOV AX,0200h INT 10h RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; HideCursor: ; Move cursor beyond lower right-hand corner. MOV DX,01951h CALL MoveCursor RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ColorPrintMsg: CALL HideCursor MOV AX,1020h MOV CX,0FFFFh MOV DI,0 CALL CREP ; Fill the screen with blue MOV AX,1BB0h MOV CX,80 MOV DI,1920 CALL CREP ; Print a blue line MOV AX,1BB1h MOV CX,80 CALL CREP ; Print another blue line MOV AX,1BB2h MOV CX,80 CALL CREP ; Print another blue line MOV AX,1BDBh MOV CX,0FFFFh CALL CREP ; color the rest of the screen ; Unfortunately, CREP destroys all registers, so after we're done ; using this, we'll reset everything back to the way it was ; when we first started. CALL InitRegs MOV AH,1Eh MOV SI,OFFSET HELLO MOV DI,04A0h CALL CPRINT CALL GetKey MOV DX,0 CALL MoveCursor RET HELLO DB "This will scroll up. Press any key.", 0 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Prints some colorful text on the screen. ; ; AH <- color ; SI <- null-terminated string location ; DI <- start offset on the screen ; CPRINT: CALL SaveRegs MOV BX,0B800h MOV ES,BX CLD nextchr: LODSB CMP AL,0 JE EXIT_RestoreRegs STOSW JMP nextchr EXIT_RestoreRegs: CALL RestoreRegs RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Repeats a certain character on the screen in color. ; ; AH <- color ; AL <- character to print ; CX <- number of times to print it ; DI <- start offset on the screen ; ; Destroys: BX,CX,ES,DI CREP: MOV BX,0B800h MOV ES,BX startprint: CMP DI,4000 JAE StopOverflow STOSW LOOP startprint StopOverflow: RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Resets all registers to original starting point. ; InitRegs: MOV AX,CS MOV DS,AX MOV ES,AX XOR AX,AX MOV BX,AX MOV CX,AX MOV DX,AX MOV SI,AX MOV DI,AX CLC CLD RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; This is supposed to be CALLed like a sub routine, ; and it will return to the caller, leaving 32 bytes ; on the stack - AX,BX,CX,DX,SI,DI,ES,DS ; ; Destroys: BP !!! SaveRegs: POP BP ; FROM address -> BP PUSH AX PUSH BX PUSH CX PUSH DX PUSH SI PUSH DI PUSH ES PUSH DS PUSH BP ; STACK <- FROM address RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; And this will pop those 32 bytes from the stack and ; "undo" what SaveRegs has done... ; ; Destroys: BP !!! RestoreRegs: POP BP ; FROM address -> BP POP DS POP ES POP DI POP SI POP DX POP CX POP BX POP AX ; JMP BP ; this might work too! (its faster) PUSH BP ; STACK <- FROM address RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Scrolls the screen up by one line. ScrollUp: CALL SaveRegs CLD MOV AX,0B800h MOV DS,AX MOV ES,AX XOR DI,DI MOV SI,160 MOV CX,4000 - 160 REP MOVSW JMP EXIT_RestoreRegs ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; PrintDec: MOV DX,84C5h MOV AX,3F91h MOV CX,10 MOV DI,OFFSET BIGNUM CALL CONVERT MOV DX,OFFSET MESSAGE MOV AX,0900h INT 21h RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Converts a LONG to a string number in any base. ; ; DX:AX <- UNSIGNED LONG ; CX <- Number base (1 to 16) ; ES:DI <- ptr to resulting string ; CONVERT: PUSH AX PUSH BX PUSH CX PUSH DX SUB SP,00004h MOV BP,SP PUSH DI XOR SI,SI XOR BH,BH MOV WORD PTR [BP],AX MOV WORD PTR [BP+002h],DX CLD CnvBin_Loop: INC SI MOV AX,WORD PTR [BP+002h] XOR DX,DX DIV CX MOV WORD PTR [BP+002],AX MOV AX,WORD PTR [BP] DIV CX MOV WORD PTR [BP],AX MOV BL,DL MOV AL,BYTE PTR [HEX+BX] STOSB CMP WORD PTR [BP],00000h JNE CnvBin_Loop CMP WORD PTR [BP+002h],00000h JNE CnvBin_Loop XOR AL,AL STOSB POP CX XCHG CX,SI SHR CX,001h JE CnvBin_End XCHG DI,SI SUB SI,00002h CnvBin_Swap: MOV AL,BYTE PTR [DI] XCHG AL,BYTE PTR [SI] STOSB DEC SI LOOP CnvBin_Swap CnvBin_End: ADD SP,00004h POP DX POP CX POP BX POP AX RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Converts a number to hex format. ; ; AL <-- Binary number ; AX --> Hex number ; ; Destroys: BX, CL toHex: MOV AH,AL AND AL,00Fh MOV BX,OFFSET HEX XLAT XCHG AH,AL MOV CL,4 SHR AL,CL XLAT RET HEX DB "0123456789ABCDEF" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Translates hex string in AX to a number value in AL ; ; Destroys: AH, CL fromHex: OR AX,2020h ; Convert to lowercase letters SUB AL,57 ; Digit or Letter? JBE DIGIT1 SUB AL,39 DIGIT1: ADD AL,99h SUB AH,57 ; Digit or Letter? JBE DIGIT2 SUB AH,39 DIGIT2: MOV CL,4 SHL AH,CL ADD AL,AH RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Converts a byte in BL to a binary string at [DS:DI] ; ; Destroys: AL, BL, CX, DI ; toBin: CLD MOV CX,8 toBin2: MOV AL,"0" SHL BL,1 JNC SaveDigit INC AL SaveDigit: STOSB LOOP toBin2 RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Converts a string to all-lowercase letters ; ; DS:SI <- pointer to null-terminated string ; ; Destroyed: None toLowerCase: PUSH AX PUSH SI CLD toLowerCase_Next: LODSB CMP AL,0 JE Endlwrcs CMP AL,"A" JB toLowerCase_Next CMP AL,"Z" JA toLowerCase_Next OR AL,020h MOV [SI-1],AL JMP toLowerCase_Next Endlwrcs: POP SI POP AX RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Converts a string to all-uppercase letters ; ; DS:SI <- pointer to null-terminated string ; ; Destroyed: None toUpperCase: PUSH AX PUSH SI CLD toUpperCase_Next: LODSB CMP AL,0 JE Endupprcs CMP AL,"a" JB toUpperCase_Next CMP AL,"z" JA toUpperCase_Next AND AL,11011111b MOV [SI-1],AL JMP toUpperCase_Next Endupprcs: POP SI POP AX RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; PrintBin: MOV BL,AL MOV DI,OFFSET BBB CALL toBin MOV DX,OFFSET BinMSG MOV AX,0900h INT 21h RET BinMSG DB 10, 13, "Binary number = " BBB DB "########", 10, 13, 36 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Clears the screen. ; CLS: CALL SaveRegs ; Move cursor to upper left-hand corner. XOR BX,BX MOV DX,BX MOV AX,0200h INT 10h ; Erase the screen by writing 2000 spaces directly ; into the video memory area at B800:0000 MOV AX,0B800h MOV ES,AX XOR DI,DI MOV CX,2000 MOV AX,0720h CLD REP STOSW CALL RestoreRegs RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; GetKey: XOR AX,AX INT 16h RET ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; PrintMsg: ; We are supposed to get a hex number in AX, ; which we will store right away MOV DI,OFFSET NUM STOSW ; then print the whole thing MOV DX,OFFSET MSG MOV AX,0900h INT 21h RET MSG DB 10, 13, "Number = " NUM DB "##" DB 10, 13, 10, 13 DB "Press any key to continue...", 10, 13, 36 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; PrintKeyCode: ; The key code is in AX MOV WORD PTR [OFFSET K],AX MOV CX,AX ; Convert low byte AL -> AX CALL toHex MOV WORD PTR [OFFSET KEY],AX ; Convert high byte MOV AL,CH CALL toHex MOV WORD PTR [OFFSET KEY2],AX MOV DX,OFFSET MSG2 MOV AX,0900h INT 21h RET MSG2 DB 10, 13, 10, 13, "According to BIOS INT 10 00, the key you pressed was : " K DB "## (" KEY1 DB "## " KEY2 DB "##)", 10, 13, 10, 13, 36 KEY DB "###", 10, 13, 10, 13, 36 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ExitProgram: MOV AX,4C00h INT 21h TEST2 DB "<<< This is a test >>>", 0 MESSAGE DB 10, 13, "The decimal number = " BIGNUM DB "$$$$$$$$$$$$$$$$$$$$$$" CODE ENDS END MAIN