; W_SCRN - A MACRO to write directly to screen ram ; ; (doesn't use BIOS) (parameters are Line#, Col#) ; ; This MACRO would usually be used to create a subroutine. When ; entering, the SI register must point to the $ terminated string ; to be printed. W_SCRN MACRO; LINE, COL PUSH AX PUSH DI PUSH ES MOV ES,SCR_SEG MOV DI, (#1 * 160 + #2 * 2) M0: MOV AL,[SI] CMP AL,'$' JE >M1 MOV ES:[DI],AL INC SI INC DI INC DI ;; Skip attribute byte JMP M0 M1: POP ES POP DI POP AX #EM ; PRINT_LM prints text with a constant left margin starting ; at a screen location stored at STARTLM as 2*COL + 160*ROW ; No registers are saved except ES, so save AX, BL, SI, DI if ; you need 'em. PRINT_LM MACRO; LMARG, STARTROW, STRING2DO PUSH ES MOV ES, SCR_SEG MOV DI, #3 ;; address of string MOV SI, (#2 * 160 + #1 * 2) MOV AX, SI ;; AX holds beginning of current line M3: MOV BL, [DI] INC DI CMP BL, 10 ;; 10 means we're finished JE > M1 CMP BL, 13 ;; 13 means end line (do linefeed) JNE > M2 ADD AX, 160 ;; drop to next line MOV SI, AX JNZ M3 ;; forced branch M2: MOV ES:[SI], BL INC SI INC SI JMP NEAR M3 M1: POP ES #EM ; A macro to write a specified # of bytes to the current cursor ; position without the need for string terminator. You must have ; DS:DX pointing to the string. This is because QUICKA can't pass text ; strings such as [BUFFER+BP] to a MACRO WRITE_SCREEN MACRO; N_BYTES MOV AH, 040h MOV BX, 1;; Handle for screen MOV CX, #1;;N_BYTES INT 021h #EM ; WRITE_TSTR writes a string terminated by a marker byte, 0 or $ for ; example, to the screen. It uses macro COUNT2C which uses FIND_BYTE WRITE_TSTR MACRO; ADDRESS, CHR COUNT2C #1, #2 MOV AH, 040h MOV BX, 1;; Handle for screen MOV DX, #1 INT 021h #EM ; COUNT2C counts the bytes in a string up to a specified byte, but not ; including it. Returns the byte count in CX COUNT2C MACRO; OFFSET, CHR FIND_BYTE #1, #2, 0FFFFh ;; allows 64K search SUB DI, #1 + 1 ;; make DI = absolute # of bytes MOV CX, DI #EM ; WRITE_VERT writes a column of fields to the screen. Parameters are: ; Offset to screen byte (ROW*160 + COL*2) ; # of characters per field ; # of fields ; Address label of character field array WRITE_VERT MACRO;; SCREEN_OFFSET, # CHARS/FIELD, #FIELDS, ADDRESS MOV ES, SCR_SEG;; B800 OR B000 MOV SI, #4 MOV BX, #1 MOV CX, #3 M0: PUSH CX MOV CX, #2 MOV DI, BX M1: MOV AL, [SI] MOV ES:[DI], AL INC SI INC DI INC DI;; Skip attribute byte on screen LOOP M1 ADD BX, 160;; drop down one row POP CX LOOP M0 #EM ; A MACRO TO FIND A BYTE IN A STRING ; Assumes string is in data segment, after finding the byte, ; DI will point to its offset + 1. ; If no match is found, the ZERO flag will be clear. FIND_BYTE MACRO; STRING, XBYTE, XLENGTH CLD ; 3.15 added 8/21/93 PUSH DS POP ES MOV DI, OFFSET #1;; String is name of string to search MOV CX, #3;; XLENGTH is max length to be searched MOV AL, #2;; XBYTE is the byte we are looking for REPNE SCASB #EM ; A macro to convert the 16 bit binary # in AX to the 4 digit text Hex ; string representing it. The string goes to an offset supplied as the ; argument. HEXTEX MACRO; STRADR PUSH AX,BX,CX,DI MOV CX,4;; Counter for 4 hex digits MOV DI, OFFSET #1 ADD DI,3;; LSD first M1: MOV BL,AL AND BL,0Fh CMP BL,0Ah JB >M2 ADD BL,'A'-10 JMP >M3 M2: ADD BL,'0' M3: MOV [DI],BL DEC DI PUSH CX MOV CX,4 SHR AX,CL POP CX LOOP M1 POP DI,CX,BX,AX ;; Put a RET here if you're using the macro as a subroutine #EM ; A MACRO to call DOS (INT 021h) and check the CRITIC variable ; and jmp to the specified address if the user ignores a critical ; error GO2DOS MACRO; BADJUMP MOV CRITIC,0;; Means critical error not ignored INT 021h CMP CRITIC,0 JE >M1 JMP #1 M1: #EM ; A MACRO TO DELAY # OF TIMER TICKS. THERE ARE 18.2 TICKS/SEC ; THE TIMER 0 INTERUPT MUST BE REDIRECTED TO MY ROUTINE MYVEC8 TICKS MACRO; TIX PUSH AX; 4.15 introduced use of AX so value could be variable MOV AX, #1 MOV VARBL, AX POP AX M1: CMP VARBL,0 JNE M1 #EM ; This macro moves a string of bytes, expected to be ; both in code segment. SMOVE MACRO; FROM, TO, N_BYTES MOV CX,#3 PUSH CS PUSH CS POP ES POP DS MOV DI,OFFSET #2 MOV SI,OFFSET #1 CLD REP MOVSB #EM ; FILL - A MACRO ; This macro fills a block of memory with the specified ; byte. FILL MACRO; CHAR, START_ADR, N_BYTES MOV CX,#3 MOV AL,#1 M1: MOV SI,CX MOV [#2-1][SI],AL LOOP M1 #EM ; READ_FILE - A MACRO READ_FILE MACRO; HANDLE, N_BYTES, BUFFER, NOERR_JMP MOV AH,03Fh;; Read file command MOV BX, #1;; Handle MOV CX, #2 ;; # of bytes to read MOV DX, OFFSET #3 INT 021h;; Call DOS JNC #4 ;; Carry clear means no error ; user's error handling code, if any, follows macro call #EM ; CURSET - A MACRO ; This macro moves the cursor to the row/column supplied in ; the parameter word, high = row, low = col. ex: 0110 means ; row 1, column 16 (hex 10). VPAGE assumed to hold video page # CURSET MACRO; ROWCOL PUSH AX,BX,DX MOV AH, 02 MOV BH,VPAGE MOV DX,#1 INT 010h POP DX,BX,AX #EM ; MACROS TO MOVE THE CURSOR TO THE START OF INFO LINES 1,2,3,4 INFO1 MACRO CURSET 01200h;; INFO LINE 1 = 18 #EM INFO2 MACRO CURSET 01300h;; INFO LINE 2 = 19 #EM INFO3 MACRO CURSET 01400;; LINE 20 #EM INFO4 MACRO CURSET 01500;; LINE 21 #EM ; PRINTL - A MACRO ; This macro prints a line to the standard output. The ; line must be terminated in a '$'. The parameter required ; is the address (offset) of the line's first byte. PRINTL MACRO; STRING PUSH BP MOV BP,OFFSET #1 CALL PRNT_LINE POP BP #EM ; PRINTLA - Print line plus attribute: ; Note: line is terminated in "$" PRINTLA MACRO; STRING, ATTR ; first, count the # of letters: FIND_BYTE #1, '$', 81; DI will point to $+1 address SUB DI, OFFSET #1 DEC DI; get # of bytes, not incl. $ MOV CX, DI ; Put # of bytes into CX MOV AH, 09h ; BIOS function MOV AL, ' ' MOV BH, VPAGE MOV BL, #2 INT 010h ; write CX spaces with attribute @ cursor ; note that above function didn't move the cursor, now write the ; string: PRINTL #1 #EM ; LOCATION - A MACRO *** REV 2.10 *** ; This Macro takes an ascii character as a parameter and ; generates code to put it to the location field without ; affecting any registers LOCATION MACRO; CHAR PUSH AX MOV AX,#1 CALL PUT_LOC POP AX #EM ; EROR - A MACRO *** REV. 2.10 ; This Macro takes an ascii character as a parameter and ; generates code to put it to the error field without ; affecting any registers EROR MACRO; CHAR MOV ERR_CHAR,#1 CALL PUT_ERCH #EM ; PSTATUS - MACRO ; Prints the addressed status message at row 22, column 0. ; Message label is parameter. Also puts the specified attribute ; to the line PSTATUS MACRO; STRING, ATTR PUSH AX,BX,DX ;; set cursor to line 22 MOV AH, 02 MOV BH,VPAGE MOV DX,22*0100h INT 010h ;; clear line and put attribute, cursor doesn't move (I hope) MOV AL, ' ' MOV BL, #2 MOV CX, 80 MOV BH, VPAGE MOV AH, 09h INT 010h ;; PUT_CHARS #2, ' ', 80 PRINTL #1 POP DX,BX,AX #EM ; PUT_CHARS this macro uses INT 10h, function 09h to put ; N chars to the screen at the current cursor position. All positions ; receive the same character and attribute. It can be used to clear ; screen, or fill an area with a particular attribute, or make a line ; VPAGE must be defined. WARNING: REGISTERS AREN'T SAVED PUT_CHARS MACRO; ATTRIB, CHAR, NUMBER MOV AL, #2 MOV BL, #1 MOV CX, #3 MOV BH, VPAGE MOV AH, 09h INT 010h #EM ;************************* drawing lines and box macros ***************** ; ; ****************** Borrowed from the FREQ source code ****************** ; Macros for drawing boxes: ; These macros can be used to draw lines or boxes, from either ; double or single lines. ; The routines write directly to screen ram ; The macros are combined into a BOX macro which can draw a ; box with just the following parameters given: ; ROW, COLUMN of upper left corner ; CHAR_SET pointer which is 0 for double lines and ; SING_SET for single lines. It uses local constant symbol S0 ; WIDTH AND HEIGHT ; COLOR attribute to be used (use color name from EQUATES list) ; When drawing without using the BOX macro, start with the POINT ; macro, which sets up the ROW, COL, CHAR_SET, and COLOR for ; subsequent macros. ; The POINT macro also sets up local constant symbols R0 AND C0 for ; later reference to ROW and COL. It also sets ES equal to the variable ; SCR_SEG which should be defined in the video init part of your program ; SCR_SEG is usually B800 for color monitors. ; POINT puts "cursor" (DI) at ROW, COL POINT MACRO; ROW, COL, CHAR_SET, COLOR MOV DI, #1*160 +#2*2 S0 EQU #3 MOV AH, #4 R0 EQU #1 C0 EQU #2 MOV ES, SCR_SEG #EM RIGHT MACRO; NUMBER, SET MOV AL, [HORIZ+S0] ;MOV AH, BOX_COLOR MOV CX, #1 CLD; increment ;MOV ES, SCR_SEG REP STOSW H1 EQU 1; Horiz direction is right #EM LEFT MACRO; NUMBER, SET MOV AL, [HORIZ+S0] ;MOV AH, BOX_COLOR MOV CX, #1 STD; decrement ;MOV ES, SCR_SEG REP STOSW H1 EQU 0; Horiz direction is left #EM UP MACRO; NUMBER, SET MOV AL, [VERT+S0] ;MOV AH, BOX_COLOR MOV CX, #1 ;MOV ES, SCR_SEG M1: MOV ES:[DI], AX SUB DI, 160; UP ONE ROW LOOP M1 V1 EQU 1; Vertical direction is up #EM DN MACRO; NUMBER, SET MOV AL, [VERT + S0] ;MOV AH, BOX_COLOR MOV CX, #1 ;MOV ES, SCR_SEG M2: MOV ES:[DI], AX ADD DI, 160; DOWN ONE ROW LOOP M2 V1 EQU 0; Vertical direction is DOWN #EM ; A86 USAGE NOTE: THE ## DOUBLE HASH'S ARE NECESSARY IF ; THE "IF" STATEMENT IS TO BE EVALUATED BASED ON THE VALUE ; OF ITS ARGUMENT WHEN THE STATEMENT IS EXPANDED. OTHERWISE, IT ; WILL BE EVALUATED ONLY WHEN THE MACRO IS READ AND THE "IF" WILL ; HAVE NO EFFECT, EVEN IF ITS ARGUMENT HAS CHANGED. ; ; ALSO, THE ARGUMENT MUST BE A LOCAL SYMBOL, SINCE A86 DOESN'T ; ALLOW REDEFINITION OF ANY OTHERS TURN_UP MACRO; NUMBER, SET MOV BL, H1 ##IF H1 MOV AL, [LRC + S0] ##ELSE MOV AL, [LLC + S0] ##ENDIF ;MOV AH, BOX_COLOR ;MOV ES, SCR_SEG MOV ES:[DI], AX SUB DI, 160; cursor up to above space UP #1-1, S0 #EM TURN_DN MACRO; NUMBER, SET ##IF H1 MOV AL, [URC + S0] ##ELSE MOV AL, [ULC + S0] ##ENDIF ;MOV AH, BOX_COLOR ;MOV ES, SCR_SEG MOV ES:[DI], AX ADD DI, 160; cursor down DN #1-1, S0 #EM TURN_RT MACRO; NUMBER, SET ##IF V1 MOV AL, [ULC + S0] ##ELSE MOV AL, [URC + S0] ##ENDIF ;MOV AH, BOX_COLOR ;MOV ES, SCR_SEG MOV ES:[DI], AX INC DI INC DI RIGHT #1-1, S0 #EM TURN_LT MACRO; NUMBER, SET MOV BL, V1 ##IF V1 MOV AL, [URC + S0] ##ELSE MOV AL, [LRC + S0] ##ENDIF ;MOV AH, BOX_COLOR ;MOV ES, SCR_SEG MOV ES:[DI], AX DEC DI DEC DI LEFT #1-1, S0 #EM ; CONNECT_V is a macro which draws a vertical connecting line ; in the down direction. It starts with a tee down, ends with a tee ; up, and puts a cross where it detects any line crossing. You ; give parameters as ROW, COL OFFSETS from the previously defined ; upper left corner, plus a length. ; To split a box in half, it should have a width of N, where N is odd ; and the COL_OFFSET should be (N-1)/2 CONNECT_V MACRO; ROW_OFFSET, COL_OFFSET, LENGTH MOV DI, (R0 + #1)*160 + (C0 + #2)*2; plot starting point MOV AL, [TEE_DN + S0] MOV ES:[DI], AL MOV BL, [HORIZ + S0]; to test for crossings MOV AL, [VERT + S0] MOV BH, [CROSS + S0] MOV CX, #3 - 2; subtract 2 for end tees M1: ADD DI, 160 CMP ES:[DI], BL JNE >M2 MOV ES:[DI], BH; install a cross JMP >M3 M2: MOV ES:[DI], AX M3: LOOP M1 ADD DI, 160 MOV AL, [TEE_UP + S0] MOV ES:[DI], AL #EM ; CONNECT_H is a macro which draws a horizontal connecting line ; in the right direction. It starts with a tee right, ends with a tee ; left, and puts a cross where it detects any line crossing. You ; give parameters as ROW, COL OFFSETS from the previously defined ; upper left corner, plus a length. ; To split a box in half, the box should have a height of N which ; is an odd number. Then the row offset should be (N-1)/2 CONNECT_H MACRO; ROW_OFFSET, COL_OFFSET, LENGTH MOV DI, (R0 + #1)*160 + (C0 + #2)*2; plot starting point MOV AL, [TEE_RT + S0] MOV ES:[DI], AL MOV BL, [VERT + S0]; to test for crossings MOV AL, [HORIZ + S0] MOV BH, [CROSS + S0] MOV CX, #3 - 2; subtract 2 for end tees M1: INC DI INC DI CMP ES:[DI], BL JNE >M2 MOV ES:[DI], BH; install a cross JMP >M3 M2: MOV ES:[DI], AX M3: LOOP M1 INC DI INC DI MOV AL, [TEE_LT + S0] MOV ES:[DI], AL #EM BOX MACRO;; ROW, COL, WIDTH, HEIGHT, SET, COLOR V1 EQU 1;; SIMULATE UP DIRECTION POINT #1, #2, #5, #6 TURN_RT #3-1, #5 TURN_DN #4-1, #5 TURN_LT #3-1, #5 TURN_UP #4-1, #5 #EM