Loops in 8051 assembly? (at89s52) - loops

I am trying to program in assembly for an at89s52 microprocessor, I have found a couple of very basic tutorials on youtube that have not helped me much since I am programming in Keil and most are in C, that is why I ask for help here.
I would like to do an insertion sort that accommodates the numbers I have, which are: 05H, 01H, 04H, 02H and 08H, but as much as I have tried I have not been able to do the cycle with which I would like to do it. I wanted to ask if someone could tell me how I could start, since I can't think of anything to do my insertion sort please, this is my code at the moment:
ORG 0000H
AJMP MAIN
ORG 0040H
MAIN:
MOV DPTR, #70H
MOV A, #05H
MOVX #DPTR, A
INC DPTR
MOV A, #01H
MOVX #DPTR, A
INC DPTR
MOV A, #04H
MOVX #DPTR, A
INC DPTR
MOV A, #02H
MOVX #DPTR, A
INC DPTR
MOV A, #08H
MOVX #DPTR, A
MOV R0, #1H
CJNE R0, #5H, CICLO
CICLO: //loop
MOV R1, R0
END

MOV DPTR, #70H
L1:
movx a, #dptr
mov r0, a
inc dptr
movx a, #dptr
mov r1, a
clr c
subb a, r0
jc less
;more
mov a, r1
movx #dptr, a
mov a, dpl
clr c
subb a, #1
jnc L2
dec dph
L2:
mov dpl, a
mov a, r0
movx #dptr, a
jmp L4
less:
mov a, r0
movx #dptr, a
mov a, dpl
clr c
subb a, #1
jnc L3
dec dph
L3:
mov dpl, a
mov a, r1
movx #dptr, a
L4:
inc dptr
mov r0, dpl
mov r1, dph
cjne r0, #70h+5-1, L1 ;Your the Low Address equelly 70h
cjne r1, #00h, L1 ;Your the High Address equelly 00h
mov dptr, #70h
jmp L1

Related

VESA mode, OSDEV

I am currently writing an OS from complete scratch(making my own bootloader etc), and I am attempting to adapt VESA mode.
I have read documentation, it all makes sense..all but just a few things.
This is directly from the documentation(I have it implemented differently):
vbe_set_mode:
mov [.width], ax
mov [.height], bx
mov [.bpp], cl
sti
push es ; some VESA BIOSes destroy ES, or so I read
mov ax, 0x4F00 ; get VBE BIOS info
mov di, vbe_info_block
int 0x10
pop es
cmp ax, 0x4F ; BIOS doesn't support VBE?
jne .error
mov ax, word[vbe_info_block.video_modes]
mov [.offset], ax
mov ax, word[vbe_info_block.video_modes+2]
mov [.segment], ax
mov ax, [.segment]
mov fs, ax
mov si, [.offset]
.find_mode:
mov dx, [fs:si]
add si, 2
mov [.offset], si
mov [.mode], dx
mov ax, 0
mov fs, ax
cmp [.mode], 0xFFFF ; end of list?
je .error
push es
mov ax, 0x4F01 ; get VBE mode info
mov cx, [.mode]
mov di, mode_info_block
int 0x10
pop es
cmp ax, 0x4F
jne .error
mov ax, [.width]
cmp ax, [mode_info_block.width]
jne .next_mode
mov ax, [.height]
cmp ax, [mode_info_block.height]
jne .next_mode
mov al, [.bpp]
cmp al, [mode_info_block.bpp]
jne .next_mode
; If we make it here, we've found the correct mode!
mov ax, [.width]
mov word[vbe_screen.width], ax
mov ax, [.height]
mov word[vbe_screen.height], ax
mov eax, [mode_info_block.framebuffer]
mov dword[vbe_screen.physical_buffer], eax
mov ax, [mode_info_block.pitch]
mov word[vbe_screen.bytes_per_line], ax
mov eax, 0
mov al, [.bpp]
mov byte[vbe_screen.bpp], al
shr eax, 3
mov dword[vbe_screen.bytes_per_pixel], eax
mov ax, [.width]
shr ax, 3
dec ax
mov word[vbe_screen.x_cur_max], ax
mov ax, [.height]
shr ax, 4
dec ax
mov word[vbe_screen.y_cur_max], ax
; Set the mode
push es
mov ax, 0x4F02
mov bx, [.mode]
or bx, 0x4000 ; enable LFB
mov di, 0 ; not sure if some BIOSes need this... anyway it doesn't hurt
int 0x10
pop es
cmp ax, 0x4F
jne .error
clc
ret
.next_mode:
mov ax, [.segment]
mov fs, ax
mov si, [.offset]
jmp .find_mode
.error:
stc
ret
.width dw 0
.height dw 0
.bpp db 0
.segment dw 0
.offset dw 0
.mode dw 0
What I am confused about is, why does it assign the segment to the video modes pointer plus 2?
I get that the video mode pointer has an offset:segment, but I am just confused as to why we assign video mode pointer + 2 to the segment, and why we add si by two after we assign the offset and segment to the dx register.
mov ax, word[vbe_info_block.video_modes]
mov [.offset], ax
mov ax, word[vbe_info_block.video_modes+2]
mov [.segment], ax
why does it assign the segment to the video modes pointer plus 2? I get that the video mode pointer has an offset:segment, but I am just confused as to why we assign video mode pointer + 2 to the segment
A far pointer is stored in memory with a word-sized offset followed by a word-sized segment.
The offset is stored at vbe_info_block.video_modes, and the segment is stored in the following word which has an address that is 2 more, so at [vbe_info_block.video_modes + 2]
mov dx, [fs:si]
add si, 2
mov [.offset], si
and why we add si by two after we assign the offset and segment to the dx register.
We don't assign the offset and segment to the DX register!
The far pointer we retrieved (and put in FS:SI) points to a list of word-sized mode numbers. It's a mode number that we load in the DX register. And the add si, 2 mov [.offset], si is there so the loop can iterate over all the words in the list.

how to pass an array of pointers to a procedure in assembly model large?

i have a C code that defines a function, the function is implemented in ASM in model large memory.
the procedure receives an array of pointers (matrix) two integers and 4 pointers. inside the function i call another procedure which receives two arrays, two pointers and one integer.
now as i understand, when the call is initiated the parameters are passed through the stack, and in model large when a pointer is passed, the offset and segment of that pointer gets passed.
my question is, how do i pass 2 arrays from the array of pointer (i.e two pointers) to the other procedure? i have no trouble passing the integer and two pointers to the other procedure (i push the offset and segment of the pointers and then push the value of the integer)
here's my ASM code:
public _find_closest_matrix_pair
_find_closest_matrix_pair proc far
push bp
mov bp,sp
push si
push di
push es
mov ax,[bp+10]
mov n,ax
mov ax,[bp+12]
mov m,ax
mov es,[bp+28]
mov bx,[bp+26]
push es
push bx
mov es,[bp+20]
mov bx,[bp+18]
push es
push bx
mov ax,m
push ax
mov si,[bp+6]
mov es,[bp+8]
mov di,si
add di,2
push es
push word ptr [di]
push es
push word ptr [si]
Call find_closest_pair
add sp,18
;get returned value:
mov min1,0
add word ptr min1,ax
adc word ptr min1+2,dx
;update indices:
mov es,[bp+20]
mov bx,[bp+18]
mov ax,es:[bx]
mov j_min1,ax
mov es,[bp+28]
mov bx,[bp+26]
mov ax,es:[bx]
mov j_min2,ax
mov cx,0
mov es,[bp+16]
mov bx,[bp+14]
mov es:[bx],cx
mov ax,es:[bx]
mov i_min1,ax
inc cx
mov es,[bp+24]
mov bx,[bp+22]
mov es:[bx],cx
mov ax,es:[bx]
mov i_min2,ax
mov si,[bp+6]
mov s,0
loop1:
mov di,si
add di,2
mov bx,s
inc bx
mov k,bx
loop2:
mov es,[bp+28]
mov bx,[bp+26]
push es
push bx
mov es,[bp+20]
mov bx,[bp+18]
push es
push bx
mov ax,m
push ax
mov es,[bp+8]
push es
push word ptr [di]
push es
push word ptr [si]
call find_closest_pair
add sp,18
;get returned value:
mov temp,0
add word ptr temp,ax
adc word ptr temp+2,dx
mov ecx,temp
cmp ecx,min1
jae continue1
mov min1,ecx
;update indices:
mov es,[bp+20]
mov bx,[bp+18]
mov ax,es:[bx]
mov j_min1,ax
mov es,[bp+28]
mov bx,[bp+26]
mov ax,es:[bx]
mov j_min2,ax
mov ax,s
mov es,[bp+16]
mov bx,[bp+14]
mov es:[bx],ax
mov i_min1,ax
mov ax,k
mov es,[bp+24]
mov bx,[bp+22]
mov es:[bx],ax
mov i_min2,ax
continue1:
add di,2
inc k
mov cx,n
cmp k,cx
jb loop2
add si,2
inc s
mov cx,n
cmp s,cx
jb loop1
mov ax,0
mov dx,0
add ax,word ptr min1
adc dx,word ptr min1+2
mov cx,i_min1
mov es,[bp+16]
mov bx,[bp+14]
mov es:[bx],cx
mov cx,j_min1
mov es,[bp+20]
mov bx,[bp+18]
mov es:[bx],cx
mov cx,i_min2
mov es,[bp+24]
mov bx,[bp+22]
mov es:[bx],cx
mov cx,j_min2
mov es,[bp+28]
mov bx,[bp+26]
mov es:[bx],cx
pop es
pop di
pop si
pop bp
ret
_find_closest_matrix_pair endp
note: find_closest_pair is the other procedure mentioned above.
thanks in advance.

assembly program to sort in special way? help please?

8086 assembly language program that sorts an array as follows:
smallest value in the array should be placed in the first cell.
second smallest value in the last cell.
third smallest value in the second cell of the array.
fourth smallest value placed in the before-last cell of the
array.
• The above procedure continues until the array is fully sorted.
Note that in the above-described sorting technique, the large values in the initial array
will end up being placed at the middle part of the array
here is my code it sorting but in normal way :
org 100h
.MODEL SMALL
.DATA
TABLE DB 9,2,6,8,5,1
B DB 6 DUP(0)
VAL1 DB 5
NL DB ' ','$'
.CODE
MOV AX,#DATA
MOV DS,AX
LEA BX,TABLE
MOV DL,VAL1
LBL1:
LEA BX,TABLE
MOV CL,5
LBL2:
MOV AL,[BX]
MOV DL,[BX+1]
CMP AL,DL
JB LBL3
MOV [BX],DL
MOV [BX+1],AL
LBL3:
INC BX
LOOP LBL2
MOV DL,VAL1
DEC DL
MOV VAL1,DL
CMP DL,00
JNE LBL1
MOV CL,6
LEA BX,TABLE
DISPLAY:
LEA DX,NL
MOV AH,09H
INT 21H
MOV DL,[BX]
ADD DL,30H
MOV AH,02H
INT 21H
INC BX
INC BX
LOOP DISPLAY
MOV AH,4CH
INT 21H
ret
Replace:
mov cl, val1
by:
mov cl, [val1]
This way it moves the content of val1 (the number 5) to cl. In the code above, it would only move the offset of val1 to cl (the same as lea cl, val1).

How to print an array in DOS x86 assembly?

I have this code to copy the array "NUMBERS" to "DEST" such that no number will repeat (in this case it should be : 1,2,5,4,7)
The code works but now I need to print the array "DEST". How can I do that ?
data segment
NUMBERS db 1,2,1,1,1,5,5,4,7,7
DEST dt ?
data ends
code segment
assume ds:data, cs:code
start: mov ax, data
mov ds, ax
mov ax, 0a0ah
mov di, offset NUMBERS
mov bx, 0h
loop2:mov cl, [di]
mov si, offset DEST
mov ch, [si]
loop1:cmp ch, cl
je dontadd
inc si
mov ch, [si]
dec ah
jnz loop1
mov si, offset DEST
add si, bx
inc bx
mov [si], cl
dontadd:mov ah, 0ah
inc di
dec al
jnz loop2
mov ah, 4ch
int 21h
code ends
end start
You can use INT 21h, AH=02h to print a single character to STDOUT.
MOV CX,10
MOV SI,OFFSET DEST
print:
MOV DL,[si]
OR DL,DL
JE done
ADD DL,'0' ; <-- Convert numeric value in DL into ASCII code
MOV AH,02h
INT 21h
MOV DL,' ' ; Throw in a space to make things pretty
INT 21h
INC SI
LOOP print
done:
If elements in NUMBERS have values over 9 then you need more elaborate conversion of the numeric values into ASCII.
First convert numbers to string then print them.You can use this two macros for printing numbers:
printstr macro str
push ax
push dx
lea dx,str
mov ah,9
int 21h
pop dx
pop cx
endm
printnum macro n
local o,w,s,n5,lb1,lb2,lb3
pusha
push si
push di
jmp w
s db 7 dup('$')
w:
mov si,0
mov cx,7
o:mov s[si],'$'
inc si
loop o
mov si,0
xor ax,ax
mov ax,n
xor dx,dx
cmp ax,0
jge n5
mov bl,'-'
mov s[si],bl
inc si
neg ax
n5:mov cx,10
div cx
or dl,30h
mov s[si],dl
xor dx,dx
inc si
cmp ax,0
jne n5
mov si,0
cmp s[si],'-'
jne lb1
inc si
lb1:mov di,si
lb3:cmp s[si],'$'
je lb2
mov al,s[si]
push ax
inc si
jmp lb3
lb2:pop ax
mov s[di],al
inc di
cmp di,si
jl lb2
printstr s
pop di
pop si
popa
endm

NASM programming - Segmentation fault(core dumped)

My program is very simple. It takes two input from the user:
an array (only 2 digit positive numbers)
a 2-digit number to be searched
output: number of times the given no. occurs in array
sample
Enter the size of array
03
Enter a number
10
Enter a number
12
Enter a number
10
Enter the number to be searched
10
Your number appeared 02 times
everything seems to be working fine but this programs gives the error
0segmentation fault(core dumped)
Please help me solve this problem
enter code here
section .data
msg1: db "Enter the size of array",10
len1: equ $-msg1
msg2: db "Enter a number",10
len2: equ $-msg2
msg3: db "Enter the number to be searched :"
len3: equ $-msg3
msg4: db "Your entered number appeared "
len4: equ $-msg4
section .bss
temp: resb 1
array: resb 100
d1: resb 1
d0: resb 1
size: resb 1
num: resb 1
ele: resb 1
time: resb 1
section .text
global _start:
_start:
;Getting the size of array
mov eax,4
mov ebx,1
mov ecx,msg1
mov edx,len1
int 80h
mov eax,3
mov ebx,0
mov ecx,d1
mov edx,1
int 80h
mov eax,3
mov ebx,0
mov ecx,d0
mov edx,2
int 80h
sub byte[d1],48
sub byte[d0],48
mov al,byte[d1]
mov bl,10
mul bl
add byte[d0],al
mov al,byte[d0]
mov byte[size],al
mov byte[temp],al
mov ebx,array
reading:
push rbx ;preserves the value of ebx
mov eax,4
mov ebx,1
mov ecx,msg2
mov edx,len2
int 80h
mov eax,3
mov ebx,0
mov ecx,d1
mov edx,1
int 80h
mov eax,3
mov ebx,0
mov ecx,d0
mov edx,2
int 80h
sub byte[d1],48
sub byte[d0],48
mov al,byte[d1]
mov bl,10
mul bl
add byte[d0],al
mov al,byte[d0]
pop rbx
mov byte[ebx],al
add ebx,1
dec byte[temp]
cmp byte[temp],0
jg reading
mov eax,4
mov ebx,1
mov ecx,msg3
mov edx,len3
int 80h
mov eax,3
mov ebx,0
mov ecx,d1
mov edx,1
int 80h
mov eax,3
mov ebx,0
mov ecx,d0
mov edx,2
int 80h
sub byte[d1],48
sub byte[d0],48
mov al,byte[d1]
mov bl,10
mul bl
add byte[d0],al
mov al,byte[d0]
mov byte[ele],al
mov cl,byte[size]
mov byte[temp],cl
mov byte[time],0
search:
mov al,byte[ebx]
cmp byte[ele],al
jne nf
jmp f
mov cl,0
f: add ebx,1
add byte[time],1
dec byte[temp]
cmp byte[temp],cl
jg search
jmp next
nf:
add ebx,1
add byte[time],0
dec byte[temp]
cmp byte[temp],cl
jg sea rch
jmp next
next:
mov eax,4
mov ebx,1
mov ecx,msg4
mov edx,len4
int 80h
movzx ax,byte[time]
mov bl,10
div bl
mov byte[d1],al
mov byte[d0],ah
add byte[d0],48
add byte[d1],48
mov eax,4
mov ebx,1
mov ecx,d1
mov edx,1
int 80h
mov eax,4
mov ebx,1
mov ecx,d0
mov edx,1``
int 80h
mov eax,1
mov ebx,0
int 80h
global _start
section .text
_start:
mov rax,1
mov rdi,1
mov rsi,msg
mov rdx,msglen
syscall
mov rax,0
mov rdi,0
mov rsi,no1
mov rdx,5
syscall
mov rax,1
mov rdi,1
mov rsi,msg1
mov rdx,msg1len
syscall
mov rax,0
mov rdi,0
mov rsi,no2
mov rdx,5
syscall
mov rax,[no1]
sub rax,30h
mov rbx,[no2]
sub rbx,30h
add rax,rbx
add rax,30h
mov [res],rax
mov rdx,2
syscall
mov rax,1
mov rdi,1
mov rsi,res
mov rdx,2
syscall
mov rax,60h
mov rdx,0
syscall
section .data
msg: db "Enter 1st Number",0x0a
msglen equ $ -msg
msg1: db "Enter 2st Number",0x0a
msg1len equ $ -msg1
msg2:db "Addition is==",0x0a
msg2len equ $ -msg2
section .bss
no1: resb 5
no2: resb 5
res: resb 15
Looking at the source, I noticed one thing. I think your 'search' loop goes out of bounds because you failed to initialize register cl; the instruction mov cl,0 is currently dead code; it is beneath an unconditional jump so it never ever gets executed.
But as I said earlier, when in doubt, use a debugger.

Resources