18

I have written the code so far as:

.code

main
 Clrscr

  mov dh,10            ;row 10

  mov dl,20            ;column 20

  call Gotoxy          ;locate cursor

  PromptForIntegers  

    WriteString       ;display string
    ReadInt           ;input integer
  ArraySum

    WriteString       ;display string
    WriteInt          ;display integer

DisplaySum  ENDP

END main

How do I get it to repeat the same steps three times using a loop, clearing the screen after each loop iteration?

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
user267288
  • 183
  • 2
  • 2
  • 4

6 Answers6

19
mov cx,3

loopstart:
   do stuff
   dec cx          ;Note:  decrementing cx and jumping on result is
   jnz loopstart   ;much faster on Intel (and possibly AMD as I haven't
                   ;tested in maybe 12 years) rather than using loop loopstart
Arthur Kalliokoski
  • 1,627
  • 12
  • 12
  • 6
    you may use `loop loopstart` instead of `dec cx` and `jnz loopstart` as long as `do stuff` preserves the cx register – PA. Feb 05 '10 at 18:43
  • 6
    @PA: Preserving cx is necessary even if you don't use `loop`. – Jeff B Feb 05 '10 at 18:50
  • 1
    This is absolutely correct since the question is about looping *three* times. However, the question title is much more generic and I think it may be useful to add that, if cx value came from a variable and not from a constant, a JBE zero instruction, to jump to the loopend before entering the loop, would be needed. – Vincenzo Pii Nov 30 '11 at 10:25
  • Which variable or register is being used as the loop counter here? – Anderson Green Mar 15 '13 at 19:43
  • @AndersonGreen: `cx`. – kirbyfan64sos Sep 09 '13 at 20:52
  • 1
    If you're making a function call inside the loop, use a different register for your counter: `bx` is preserved across function calls in 32 and 64bit ABIs, and I assume also in 16bit ABIs. And yes, `loop` [is slow](http://stackoverflow.com/questions/35742570/why-is-the-loop-instruction-slow-couldnt-intel-have-implemented-it-efficiently). Don't use it, and don't fall into the trap of thinking that you need a separate loop counter if you can instead just test a pointer or something that you already need in the loop. (e.g. `cmp si,bx / jb` at the bottom.) – Peter Cordes Mar 13 '16 at 11:45
13

Yet another method is using the LOOP instruction:

mov  cx, 3

myloop:
    ; Your loop content

    loop myloop

The loop instruction automatically decrements cx, and only jumps if cx != 0. There are also LOOPE, and LOOPNE variants, if you want to do some additional check for your loop to break out early.

If you want to modify cx during your loop, make sure to push it onto the stack before the loop content, and pop it off after:

mov  cx, 3

myloop:
    push cx
    ; Your loop content
    pop  cx

    loop myloop
Jeff B
  • 29,943
  • 7
  • 61
  • 90
  • `loop` [is slow, and using it is not a good habit](http://stackoverflow.com/questions/35742570/why-is-the-loop-instruction-slow-couldnt-intel-have-implemented-it-efficiently). If you need ecx for something inside your loop (e.g. a shift instruction), then just use a different register for the loop counter. Having a push/pop in the loop-counter dependency chain is just silly. Usually loops need some kind of induction variable, so just test that. e.g. increment a pointer by 4 each time through the loop, and `cmp / jb` against an end pointer as the loop condition. – Peter Cordes Mar 13 '16 at 11:27
4

Use the CX register to count the loops

mov cx, 3
startloop:
   cmp cx, 0
   jz endofloop
   push cx
loopy:
   Call ClrScr
   pop cx
   dec cx
   jmp startloop
endofloop:
   ; Loop ended
   ; Do what ever you have to do here

This simply loops around 3 times calling ClrScr, pushing the CX register onto the stack, comparing to 0, jumping if ZeroFlag is set then jump to endofloop. Notice how the contents of CX is pushed/popped on/off the stack to maintain the flow of the loop.

t0mm13b
  • 34,087
  • 8
  • 78
  • 110
  • 2
    a couple of optimizations: (1)you may use `jcxz label` instead of `cmp cx,0` and `jz label`. (2) you may use `loop label` instead of `dec cx` and `jnz label` – PA. Feb 05 '10 at 18:46
  • @PA: Depending on your processor, `jcxz label` and `cmp/jz` are equivalent. Recent x86 processor use macro-fusion to combine cmp/jmp instructions into a single cycle instruction, essentially replicating `jcxz` behavior on the fly. – Jeff B Feb 05 '10 at 19:01
  • This loop is incredibly inefficient. If a loop might run zero times, then test the counter outside the loop. Then use a conditional branch at the end of the loop. And use a register that you won't need to push/pop as your loop variable. (e.g. a call-preserved register like (e/r)bx or (e)si if there are function calls in your loop.). And Jeff B is right: `cmp/jz` or `dec/jz` is *cheaper* than `jcxz` on modern CPUs like Intel Haswell. See http://agner.org/optimize/ – Peter Cordes Mar 13 '16 at 11:34
2
.model small
.stack 100h
.code 
Main proc
Mov cx , 30 ; //that number control the loop 30 means the loop will 
;excite 30 time 
Ioopfront:
Mov ah , 1
Int 21h 
Loop loopfront; 

this cod will take 30 character

FoldFence
  • 2,674
  • 4
  • 33
  • 57
rafeef
  • 21
  • 1
0

I was looking for same answer & found this info from wiki useful: Loop Instructions

The loop instruction decrements ECX and jumps to the address specified by arg unless decrementing ECX caused its value to become zero. For example:

 mov ecx, 5
 start_loop:
 ; the code here would be executed 5 times
 loop start_loop

loop does not set any flags.

loopx arg

These loop instructions decrement ECX and jump to the address specified by arg if their condition is satisfied (that is, a specific flag is set), unless decrementing ECX caused its value to become zero.

  • loope loop if equal

  • loopne loop if not equal

  • loopnz loop if not zero

  • loopz loop if zero

Source: X86 Assembly, Control Flow

Pranav Singh
  • 17,079
  • 30
  • 77
  • 104
0

You need to use conditional jmp commands. This isn't the same syntax as you're using; looks like MASM, but using GAS here's an example from some code I wrote to calculate gcd:

gcd_alg:
    subl    %ecx, %eax      /* a = a - c */
    cmpl    $0, %eax        /* if a == 0 */
    je      gcd_done        /* jump to end */
    cmpl    %ecx, %eax      /* if a < c */
    jl      gcd_preswap     /* swap and start over */
    jmp     gcd_alg         /* keep subtracting */

Basically, I compare two registers with the cmpl instruction (compare long). If it is less the JL (jump less) instruction jumps to the preswap location, otherwise it jumps back to the same label.

As for clearing the screen, that depends on the system you're using.

  • `sub %ecx, %eax` already sets ZF if the result is zero, you don't need the `cmp $0, %eax`. And you should structure the branch at the end of the loop the other way: `jnl gcd_alg` / else fall through into `gcd_preswap`. Actually, flags are still set from `sub`, so you can `sub %ecx, %eax / jnl gcd_alg / je gcd_done / fall-through into gcd_preswap`, so the main loop is two instructions. Or just use div to get the remainder if `a` might be many times greater than `c`. – Peter Cordes Mar 13 '16 at 11:39