Summary: These directives are new to MASM 6.0.
The high-level control structures new to MASM 6.0 generate loop structures for you. These new directives are similar to the while and repeat loops of C or Pascal. They can make your assembly programs less repetitive and easier to code, as well as easier to read. The assembler generates the appropriate assembly code. The .BREAK and .CONTINUE directives are also implemented to interrupt loop execution. These directives are summarized in the following list:
Directives | Action | |
.WHILE, .ENDW | The statements between .WHILE condition and .ENDW execute while the condition is true. | |
.REPEAT, .UNTIL | The loop executes at least once and continues until the condition given after .UNTIL is true. Generates conditional jumps. | |
.REPEAT, .UNTILCXZ | Compares label to an expression and generates appropriate loop instructions. |
These constructs work much as they do in a high-level language such as C or Pascal. Keep in mind the following points:
These directives generate appropriate processor instructions. They are not new instructions.
They require proper use of signed and unsigned data declarations.
These directives cause a set of instructions to execute based on the evaluation of some condition. This condition can be an expression that evaluates to a negative or nonnegative value, an expression using the binary operators in C (&&, ||, or !), or the state of a flag. See Section 7.2.2.1 for more information about expression operators.
The evaluation of the condition requires the assembler to know if the operands in the condition are signed or unsigned. To state explicitly that a named memory location contains a signed integer, use the signed data allocation directives: SBYTE, SWORD, and SDWORD.
As with while loops in C or Pascal, the test condition for .WHILE is checked before the statements inside the loop execute. If the test condition is false, the loop does not execute. While the condition is true, the statements inside the loop repeat.
Use the .ENDW directive to mark the end of the .WHILE loop. When the condition becomes false, program execution begins at the first statement following the .ENDW directive. The .WHILE directive generates appropriate compare and jump statements. The syntax is
.WHILE condition
statements
.ENDW
For example, this loop copies one buffer to another until a `$' character (marking the end of the string) is found:
.DATA
buf1 BYTE "This is a string",'$'
buf2 BYTE 100 DUP (?)
.CODE
sub bx, bx ; Zero out bx
.WHILE (buf1[bx] != '$')
mov al, buf1[bx] ; Get a character
mov buf2[bx], al ; Move it to buffer 2
inc bx ; Count forward
.ENDW
MASM's .REPEAT directive allows for loop constructions like the do loop of C and the REPEAT loop of Pascal. The loop executes until the condition following the .UNTIL (or .UNTILCXZ) directive becomes true. Since the condition is checked at the end of the loop, the loop always executes at least once. The .REPEAT directive generates conditional jumps. The syntax is:
.REPEAT
statements
.UNTILcondition
.REPEAT
statements
.UNTILCXZ [[condition]]
Summary: A condition is optional with .UNTILCXZ.
where condition can also be expr1 == expr2 or expr1 != expr2. When two conditions are used, expr2 can be an immediate expression, a register, or (if expr1 is a register) a memory location.
For example, the following code fills up a buffer with characters typed at the keyboard. The loop ends when the ENTER key (character 13) is pressed:
.DATA
buffer BYTE 100 DUP (0)
.CODE
sub bx, bx ; Zero out bx
.REPEAT
mov ah, 01h
int 21h ; Get a key
mov buffer[bx], al ; Put it in the buffer
inc bx ; Increment the count
.UNTIL (al == 13) ; Continue until al is 13
The .UNTIL directive generates conditional jumps, but the .UNTILCXZ directive generates a LOOP instruction, as shown by the listing file code for these examples. In a listing file, assembler-generated code is preceded by an asterisk.
ASSUME bx:PTR SomeStruct
.REPEAT
*@C0001:
inc ax
.UNTIL ax==6
* cmp ax, 006h
* jne @C0001
.REPEAT
*@C0003:
mov ax, 1
.UNTILCXZ
* loop @C0003
.REPEAT
*@C0004:
.UNTILCXZ [bx].field != 6
* cmp [bx].field, 006h
* loope @C0004
Summary: .BREAK and .CONTINUE interrupt loop execution.
The .BREAK and .CONTINUE directives can be used to terminate a .REPEAT or .WHILE loop prematurely. These directives allow an optional .IF clause for conditional breaks. The syntax is
.BREAK [[.IF condition]]
.CONTINUE [[.IF condition]]
Note that .ENDIF is not used with the .IF forms of .BREAK and .CONTINUE in this context. The .BREAK and .CONTINUE directives work the same way as the break and continue instructions in C. Execution continues at the instruction following the .UNTIL, .UNTILCXZ, or .ENDW of the nearest enclosing loop.
Instead of causing the loop execution to end as .BREAK does, .CONTINUE causes loop execution to jump directly to the code that evaluates the loop condition of the nearest enclosing loop.
The following loop accepts only the keys in the range `0' to `9' and terminates when ENTER is pressed.
.WHILE 1 ; Loop forever
mov ah, 08h ; Get key without echo
int 21h
.BREAK .IF al == 13 ; If ENTER, break out of the loop
.CONTINUE .IF (al < '0') || (al > '9')
; If not a digit, continue looping
mov dl, al ; Save the character for processing
mov ah, 02h ; Output the character
int 21h
.ENDW
If you assemble the source code above with the /Fl and /Sg command-line options and then view the results in the listing file, you would see this code:
.WHILE 1
0017 *@C0001:
0017 B4 08 mov ah, 08h
0019 CD 21 int 21h
.BREAK .IF al == 13
001B 3C 0D * cmp al, 00Dh
001D 74 10 * je @C0002
.CONTINUE .IF (al '0') || (al '9')
001F 3C 30 * cmp al, '0'
0021 72 F4 * jb @C0001
0023 3C 39 * cmp al, '9'
0025 77 F0 * ja @C0001
0027 8A D0 mov dl, al
0029 B4 02 mov ah, 02h
002B CD 21 int 21h
.ENDW
002D EB E8 * jmp @C0001
002F *@C0002:
The high-level control structures can be nested. That is, .REPEAT or .WHILE loops can contain .REPEAT or .WHILE loops as well as .IF statements.
If the code generated by a .WHILE loop, .REPEAT loop, or .IF statement generates a conditional or unconditional jump, MASM uses the jump extension and jump optimization techniques described in Sections 7.1.1, “Unconditional Jumps,” and 7.1.2, “Conditional Jumps,” to encode the jump appropriately.