Assembly x86 Delay loop - loops

hi i made program that will rotate two symbols - \ and / but i dont know how to set cx counter in nested loops can someone give me advice or help me ?
here is the code of that part
program:
mov ah, 0fh ; function - get video mode
int 10h
push ax ; save number of columns
push bx ; save page number
mov ah, 0 ; function - set video mode
int 10h
mov al, 0003h ;set video mode
int 10h
mov cx,10d ; Outer loop counter how many symbols rotate
mov bx,50d ; this is for delay loop
OuterLoop:
push cx
mov ah,02h
mov bh, 0 ;cursor set
mov dh, 2
mov dl, 10
int 10h
mov AH,0Ah
mov al,"/" symbol /
mov bh,0
mov cx,1
int 10h
mov cx,bx
call Delay ;delay loop
sub bx,15d
mov ah,02h
mov bh, 0
mov dh, 2 cursor set
mov dl, 10
int 10h
mov AH,0Ah
mov al,"\" ;symbol \
mov bh,0
mov cx,1
int 10h
mov cx,bx
call Delay ; another delay
sub bx,10
pop cx ; Restore current CX
loop OuterLoop
jmp START ; and after end it should jump to start where is menu with choices
it should work like this
write /
delay for example 10 sec
write \
delay 8 sec
and jump to beginning and loop
thanks for advices
this is my delay procedure
Delay PROC NEAR ;
push ds ;
push si ;
push ax ;
xor ax, ax ;AX = 0
mov ds, ax ;DS = 0
mov si, 046Ch ;
t1: mov ax, [si] ;
t2: cmp ax, [si] ;
je t2 ;
loop t1 ;
pop ax ;
pop si ;
pop ds ;
ret ;
Delay ENDP ;
i am still working on this app but it is not working all i need is this steps to be made
program : start of loop
\
delay delay 100 times
/
delay delay 80 times
loop
and after every loop to decrease delay like this 100 times 80,60,40 and so on but i dont know where to put push and pop cx because my delay procedure is working with cx. i just set cx for example to 100 and it makes delay and so on.

I see two problems:
First, bx is initialized here
mov bx,50d ; this is for delay loop
but then it gets over-written by
mov bh, 0
bh is bits 15:8 of bx
Second, in the Delay procedure, what modifies the location at [si] so that the je t2 branch falls thru? As it stands that is an infinite loop:
xor ax, ax ;AX = 0
mov ds, ax ;DS = 0
mov si, 046Ch ;
t1: mov ax, [si] ;
t2: cmp ax, [si] ;
je t2 ;
loop t1 ;
Update:
I found that address 0x46c is a BIOS address that contains time information.
http://www.osdata.com/system/physical/lowmem.htm
So the memory you are watching in that loop is a location updated by BIOS with a counter of timer ticks (counts every 54.9 milliseconds), see
http://code.google.com/p/xtideuniversalbios/source/browse/trunk/Assembly_Library/Src/Time/TimerTicks.asm?spec=svn131&r=131
So to answer your question, before calling your Delay procedure you should load CX with the count of BIOS ticks you wish to delay (time in milliseconds divided by 54.9).

For to drawing my own cursor i use the timer interrupt for to become a more steady delay on different performant CPUs.
Cursor_Speed = 7
;-------------DATA--------------------------------------
CURFLAG DB 0, 0, 0, 0
ALTVEC DD 0
;-------------CODE--------------------------------------
cli
xor ax, ax
mov es, ax
mov ebx, DWORD PTR es:[8*4] ; Get the old Vector (Offset/Segment)
mov DWORD PTR[ALTVEC], ebx ; save it
mov cs:DWORD PTR[OLDVEC], ebx
mov es:[8*4], OFFSET NEWVEC ; Set the new IRQ-Vector
mov es:[(8*4)+2], cs
mov al, 36h ; Set 18,2 Hertz(Standard)
out 43h, al
xor al, al
out 40h, al ; low
out 40h, al ; high
sti
;---------------------------------------------------
......
;---------------------------------------------------
NEWVEC: inc BYTE PTR[CURFLAG+1]
cmp BYTE PTR[CURFLAG+1], Cursor_Speed
jb short NOHIT
mov BYTE PTR[CURFLAG+1], 0
xor BYTE PTR[CURFLAG], 1
NOHIT: DB 0EAh ; jmp far
OLDVEC DD 0
;---------------------------------------------------
....
Alternativly we can wait of the vsinc with polling port 3DAh for to become a little bit lesser precice delay.
Dirk

Related

(Assembly Language) I'm trying to get a string to move across the screen 5 times before stopping

As the title states, I'm using assembly language to try to get a text to move left to right 5 times. I've pasted my code below. As of right now, what happens is it moves left to right 4 and a half times, starts over at the very left and it repeats infinity times. I feel like the error lies on where I placed my pop cx. I hope that maybe someone else can see the mistake and I just missed it.
.model small
.stack
.data
strg db 'Test$'
row db 12
col db 0
.code
main proc
mov ax,#data
mov ds,ax
dem: mov cx,5
push cx
mov cx,79
again: push cx ;clears the terminal
mov ah,6
mov al,0
mov bh,7
mov ch,0
mov cl,0
mov dh,24
mov dl,79
int 10h
mov ah,2
mov bh,0
mov dh,row ;row
mov dl,col ;col
int 10h
mov ah,9
mov dx, offset strg ;prints the text
int 21h
inc col
mov cx,1 ;x and y adds delay
y: push cx
mov cx,0ffffh
x: loop x
pop cx
loop y
pop cx
loop again
pop cx
loop dem
mov ah,4ch
int 21h
main endp
end main
what happens is it moves left to right 4 and a half times, starts over at the very left and it repeats infinity times.
I don't see where you get that '4 and a half times'. The infinite behaviour starts right away.
dem: mov cx,5
push cx
Your outer loop should initialize its counter outside of the loop.
mov cx,5
dem: push cx
I feel like the error lies on where I placed my pop cx.
Because your program uses the CX register for a lot of things, it is easy to loose track. Consider using a system that numbers what you push/pop on the stack:
mov cx,5
dem:
push cx ; (1) Outer loop
mov cx,79
again:
push cx ; (2) Inner loop
mov ah,6
mov al,0
mov bh,7
mov ch,0
mov cl,0
mov dh,24
mov dl,79
int 10h
mov ah,2
mov bh,0
mov dh,row
mov dl,col
int 10h
mov ah,9
mov dx, offset strg
int 21h
inc col
mov cx,1
y: push cx ; (3) Waiting loop
mov cx,0ffffh
x: loop x
pop cx ; (3)
loop y
pop cx ; (2)
loop again
pop cx ; (1)
loop dem
You don't always need to use CX. There are more registers at your disposal:
mov bp,1
y: mov cx,0ffffh
x: loop x
dec bp
jnz y

Asm Assembler - CX loop never executes

I have a vector and I have to put in the AX register the sum of the numbers that are greater than 50 ( > 50 ).
I do not understand why my loop does not work when I run it. First it compares 100 with 50, jumps at adunare , add 100 to AX but then it exits the loop and terminates the program.
.MODEL SMALL
.STACK 10h
.DATA
vect DB 100,70,3,10,60,200,30
len DB 7
.CODE
begin:
mov ax,#DATA
mov ds,ax
mov ax,0
mov cl,len
mov ch,0
mov si, -1
bucla:
inc si
cmp vect[si],50
ja adunare
jb mic
adunare:
add ax, word ptr vect[si]
mic:
loop bucla
mov ah,4ch
int 21h
END begin
.STACK 10h
With such a small stack the debugger could very well terminate your program as soon as an interrupt occurs, leaving you thinking that the loop doesn't execute.
Specify a larger stack. 256 bytes is a reasonable minimum.
adunare:
add ax, word ptr vect[si]
To add the byte at vect[si] to the word in AX, you have several options:
using an intermediate register like zx485 suggested
clearing the extra register:
xor dx, dx
mov dl, vect[si]
add ax, dx
extending from byte to word in one instruction:
movzx dx, vect[si]
add ax, dx
without an extra register but using a cascaded addition:
add al, vect[si]
adc ah, 0
cmp vect[si],50
ja adunare
jb mic
adunare:
add ax, word ptr vect[si]
mic:
loop bucla
You can write this simpler and if the number 50 were present in the array, it would erroneously be added to the sum. Besides the above and below conditions there's also the equal condition to take care of.
cmp vect[si], 50
jna mic
add al, vect[si]
adc ah, 0
mic:
loop bucla
For perfection you could dismiss the loop instruction (it has a reputation for being slow) and use instead dec cx jnz bucla. This in turn gives you the opportunity to not having to zero CH and rather use dec cl jnz bucla.
Everything together:
xor ax, ax ; This makes AX=0
mov cl, len
mov si, -1
bucla:
inc si
cmp vect[si], 50
jna mic
add al, vect[si]
adc ah, 0
mic:
dec cl
jnz bucla
mov ah, 4ch ; DOS.Terminate (exitcode is in AL)
int 21h
I've tested a good number of variations.
This is a faster version of the loop:
xor ax, ax ; This makes AX=0
xor si, si
mov cl, len
bucla:
cmp vect[si], 50
jna mic
xor dx, dx
mov dl, vect[si]
add ax, dx
mic:
inc si
dec cl
jnz bucla

Assembly two-dimensional array of pixels

How could I do something like this in assembly? DOS 16bit graphic mode
int start_x=1, start_y=1;
for(int i=0; i<8; i++){
for(int j=0; j<8; j++){
if(T34[i][j]==1) put_colour_pixel(start_x+i, start_y+j);
else put_black_pixel(start_x+i, start_y+j);
}
}
:edit:
So my loops pretty work. How to connect it to table with 0 and 1.
mov ax, 10 ; Y start line
mov bx, 20 ; X start line
mov dl, 4 ; colour (red)
mov cx, 5 ; loop top counter
top:
add ax, 1
push cx ;loop top counter
mov cx, 10
inside:
add bx, 1
push ax
push bx
push cx
call putpixel
pop cx
pop bx
pop ax
loop inside
mov bx, 20 ;next line X go to start X
pop cx ;loop top counter
loop top
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
My new code:
segment .data
segment .code
..start:
mov ax, 13h
int 10h ; switch to 320x200 mode
mov ax, 0a000h ; The offset to video memory
mov es, ax ; We load it to ES through AX,
; because immediate operation
; is not allowed on ES
;;;;;;;;;;;;;;;;;;;;;;
mov di, T34
mov si, 8
;------------------------------------
P1: mov bp, 8
;----------------
P2: cmp BYTE[di], 1
jnz short NOHIT
NOHIT: ; increase the x position
push ax
push bx
push cx
mov ax,si ;Y
mov bx,bp ;X
mov dl, 1 ; here I should take '0' or '1' from table
call putpixel
pop cx
pop bx
pop ax
inc di ; increase offset address of array
dec bp
jnz P2
;-------------
; increase the y position + substract 8 from x position
dec si
jnz P1
;------------------------------------
;;;;;;;;;;;;;;;;;;;;;;;;;
xor ah, ah
int 16h ; keyboard (wait for key)
mov ax, 3
int 10h ; go to text mode
mov ax, 4c00h
int 21h ; return to DOS, exit code 0
;;;;;;;;;;;;;;;;;;;;;
putpixel:
push dx ; mul changes dx too
mov cx, 320
mul cx ; multiply Y (ax) by 320 (one row)
add ax, bx ; and add X (bx) (result= dx:ax)
mov di, ax
pop dx
mov [es:di], dl ; store color/pixel
ret
;;;;;;;;;;;;;;;;;;;;;;
T34 DB 1,1,1,1,1,1,1,1
DB 1,0,0,0,0,0,0,0
DB 1,0,0,0,0,0,0,0
DB 1,0,0,0,0,0,0,0
DB 1,1,1,1,1,1,1,1
DB 1,0,0,0,0,0,0,0
DB 1,0,0,0,0,0,0,0
DB 1,1,1,1,1,1,1,1
I have changed order and now it is drawing square in left corner (as I expected). Did I change order rigth?
I suppose that letter will be spinned, but it is not problem for me. I can fix it later.
Now I should go to '0' or '1' in table and set color. Which register have "0" or "1"?
So mostly I have problem with colour.
I have try this, but I have error. I have try set colour black (0) or blue (1)
push dx
mov ax, bp ; X*8
mov cx,8
mul cx
add ax, si ; X*8 +Y
add ax, di ; tab0 + X*8+Y
mov dl, ax; here is error, here I set the colour
pop dx
So I don't know how to fix it :( I have try different possibilities and northing work.
mov di, T34
mov si, 8
;------------------------------------
P1: mov bp, 8
;----------------
P2: cmp BYTE[di], 1
jnz short NOHIT
; save used REGISTER
; load register with the X,Y position and color
call putpixel
; get back the saved Register
NOHIT: ; increase the x position
inc di ; increase offset address of array
dec bp ; decrease counter and set zeroflag if register is zero
jnz P2 ; jump if zeroflag is not set
;-------------
; increase the y position + substract 8 from x position
dec si
jnz P1
;------------------------------------
It is also possible to start the counters for the loops with 0 for to increase the counter, but then we need a compare instruction for to leave the loop, if we want to run the loop from 0 to 8. The offset addresses inside of the array are pointed independent with no relationship to the counters.
With a little modifying (put an additional jump instruction in the code and a second call) it is also possible to set a black pixel if the byte of the array is 0. But i think this simple form of a nested loop is easier to understand in the first time.
Edit: Now it is compatible for NASM.
Edit2: Maybe it is more simple to store the x,y coordinates into a known ram location for modifying and reloading inside of a loop, if many parameters are in use.
Our ram location:
Color DB ? ; define byte
X_Pos DW ? ; define word
Y_Pos DW ?
Examples for to show how to access a memory location (default segment is DS):
mov [X_Pos], ax
mov [X_Pos], bx
mov [Color], dl
mov ax, [X_Pos]
mov bx, [Y_Pos]
mov dl, [Color]
mov WORD[X_Pos], 10
inc WORD[X_Pos]
sub WORD[X_Pos], 8
mov BYTE[Color], 4
inc BYTE[Color]
Edit3:
mov dl, ax; here is error, here I set the colour
It is not possible to mix an 8 bit register with a 16 Bit register.
Note:
AX = AL+AH
DX = DL+DH
Existing instruction are:
mov dl, al
mov dl, ah
mov dx, ax
movzx dl, ax

Assembly graphic couldn't display right colour from array

Welcome.
I could't get values from 2d array. I am trying and trying and it doesn't work. I use NASM 16 DOS
I want to have blue letter E on red backgroung. I only get square random colours.
'1' in array is blue,'4' is red. It could be spinned, but it doesn't matter.
I have no idea what is wrong. I'm trying to do this a couple od days.
Here is my code:
segment .data
segment .code
..start:
mov ax, 13h
int 10h ; switch to 320x200 mode
mov ax, 0a000h ; The offset to video memory
mov es, ax ; We load it to ES through AX,
; because immediate operation
; is not allowed on ES
;;;;;;;;;;;;;;;;;;;;;;
mov si, T34 ; my array
mov word [Y_Start], 10 ; Y start line count values in register
mov word [X_Start], 20 ; X start line
mov word [Y], 10 ; Y start line
mov word [X], 20 ; X start line
mov dx, 4 ; colour (red)
mov cx, 8 ; loop top counter
top:
add word [Y], 1
push cx ;loop top counter =
mov cx, 8 ;inside loop counter
inside:
add word [X], 1
;////////////////////////////////////////////// count colour
push ax ; remember value before procedure
push bx
push cx
push dx
mov ax, word [X]
mov cx,8
mul cx ;X*8
add ax, word[Y] ; X*8 +Y
mov cx,4
mul cx ; (X*8+Y)*4
add ax, si ; tab0 + (X*8+Y)*4
pop dx
mov dx, ax; colour
pop cx
pop bx
pop ax
;///////////////////////////////////////////
mov ax, word [Y]
mov bx, word [X]
push ax ; remember value before procedure
push bx
push cx
call putpixel
pop cx ; go back to old values
pop bx
pop ax
loop inside
mov bx, word [X_Start] ; move to X start
mov word [X], bx ;
pop cx ;loop top counter
loop top
;;;;;;;;;;;;;;;;;;;;;;;;;
xor ah, ah
int 16h ; keyboard (wait for key)
mov ax, 3
int 10h ; go to text mode
mov ax, 4c00h
int 21h ; return to DOS, exit code 0
;;;;;;;;;;;;;;;;;;;;;
putpixel:
push dx ; mul changes dx too
mov cx, 320
mul cx ; multiply Y (ax) by 320 (one row)
add ax, bx ; and add X (bx) (result= dx:ax)
mov di, ax
pop dx
mov [es:di], dx ; store color/pixel
ret
;;;;;;;;;;;;;;;;;;;;;;
X_Start DW 0 ; start letter position
Y_Start DW 0
X DW 0 ;current letter position
Y DW 0
T34 DB 1,1,1,1,1,1,1,1
DB 1,4,4,4,4,4,4,4
DB 1,4,4,4,4,4,4,4
DB 1,4,4,4,4,4,4,4
DB 1,1,1,1,1,1,1,1
DB 1,4,4,4,4,4,4,4
DB 1,4,4,4,4,4,4,4
DB 1,1,1,1,1,1,1,1
I didn't catch your approach, but I can show you how I would do it:
segment .code
..start:
mov ax, data ; Initialize DS (needed for .exe-program)
mov ds, ax
mov ax, 0A000h ; Segment to video memory
mov es, ax
mov ax, 13h
int 10h ; Switch to 320x200 mode
mov si, T34 ; DS:SI = letter
mov bx, [X_Start]
mov ax, [Y_Start]
call vector_to_memory
mov di, ax ; ES:DI = video memory
call paint
; once more
add word [X_Start], 8 ; That's one small step for a man
mov si, T34 ; DS:SI = letter
mov bx, [X_Start]
mov ax, [Y_Start]
call vector_to_memory
mov di, ax ; ES:DI = video memory
call paint
xor ah, ah
int 16h ; keyboard (wait for key)
mov ax, 3
int 10h ; go to text mode
mov ax, 4c00h
int 21h ; return to DOS, exit code 0
paint: ; Args: DS:SI = letter, ES:DI: video memory
mov ax, 8
.l1:
mov cx, 8 ; repetition count for REP
rep movsb ; CX times (one row): [DS:SI] => [ES:DI], SI++, DI++
add di, (320-8) ; next row
sub ax, 1 ; no row left?
jnz .l1 ; no: once more
ret ; yes: paint is done, return
vector_to_memory: ; Args: BX = X, AX = Y
push dx ; mul changes dx too
mov cx, 320 ; video mode width
mul cx ; DX:AX = AX * CX
add ax, bx ; left indentation
pop dx
ret ; Return: AX = offset in memory
segment .data
T34:
DB 1,1,1,1,1,1,1,1
DB 1,4,4,4,4,4,4,4
DB 1,4,4,4,4,4,4,4
DB 1,4,4,4,4,4,4,4
DB 1,1,1,1,1,1,1,1
DB 1,4,4,4,4,4,4,4
DB 1,4,4,4,4,4,4,4
DB 1,1,1,1,1,1,1,1
X_Start DW 10 ; start letter position
Y_Start DW 20
segment stack stack
resb 0x1000
HTH
You're not loading the pixel values correctly:
add ax, si ; tab0 + (X*8+Y)*4
mov dx, ax; colour <-- Here you're just copying the _address_, you're
not loading the value stored at that address.
Those two instructions should be changed to:
add si,ax
mov dl,[si]
Note the use of dl since you're dealing with bytes. I also switched the add around because [ax] wouldn't be a valid effective address. This means that you'll have to reload si with the address of the array on every iteration of the loop.
The line mov [es:di], dx in putpixel should also be changed to mov [es:di], dl.
Some of your multiplications could be simplified: to multiply a register by 4 you can do shl reg,2, and to multiply by 8 you can do shl reg,3.

How to loop in assembly language

How would I calculate the first 12 values in the Fibonacci number sequence and be able to place it in EAX reg. and display calling DumpRegs? Using Indirect addressing I know I need a for loop here but I'm not sure how to even go about this. Any help or tips are appreciated.
INCLUDE Irvine32.inc
; (insert symbol definitions here)
.data
; (insert variables here)
Fibonacci BYTE 1, 1, 10 DUP (?)
.code
main PROC
; (insert executable instructions here)
; (This below will show hexa contents of string.)
mov esi, OFFSET Fibonacci ; offset the variables
mov ebx,1 ; byte format
mov ecx, SIZEOF Fibonacci ; counter
call dumpMem
exit ; exit to operating system
main ENDP
; (insert additional procedures here)
END main
You can make a loop like this:
mov ecx,12
your_label:
; your code
loop your_label
The loop instruction decrements ecx and jumps to the specified label unless ecx is equal to zero. You could also construct the same loop like this:
mov ecx,12
your_label:
; your code
dec ecx
jnz your_label
You determined that you need a for loop to achieve your goal, so maybe the C implementation of the for loop, in assembly, will help you:
Code Generation for For Loop
for (i=0; i < 100; i++)
{
. . .
}
* Data Register D2 is used to implement i.
* Set D2 to zero (i=0)
CLR.L D2
L1
. . .
* Increment i for (i++)
ADDQ.L #1, D2
* Check for the for loop exit condition ( i < 100)
CMPI.L #100, D2
* Branch to the beginning of for loop if less than flag is set
BLT.S L1
SOURCE: eventhelix.com
.model small
.stack 100h
.data
msg db 'Enter height of the square form 1-9: $'
hash db '#$'
height db 1
length db 0
ctr dw 0
msgagain db 13,10,'Do you want to repeat the program? $'
msgend db 13,10,'Program Terminated! Press any key to exit..$'
.code
mov ax, #data
mov ds, ax
REPEAT:
mov ax, 03
int 10h
mov ah, 09
lea dx, msg
int 21h
mov ah, 01
int 21h
cmp al, '1'
jl REPEAT
cmp al, '9'
jg REPEAT
sub al, 48
mov length, al
mov bl, 1
mul bl
mov height, 1
mov di, 1
mov ctr, ax
mov cx, ax
nextline:
dec length
mov ah, 02
mov bh, 00
mov dl, length
mov dh, height
int 10h
mov cx, di
hashtags:
mov ah, 09
lea dx, hash
int 21h
loop hashtags
inc di
inc height
mov cx, ctr
dec ctr
loop nextline
mov ah, 09
lea dx, msgagain
int 21h
mov ah, 01
int 21h
cmp al, 'Y'
je REPEAT
cmp al, 'y'
je REPEAT
mov ah, 09
lea dx, msgend
int 21h
mov ah, 01
int 21h
mov ah, 4ch
int 21h
END

Resources