The following is my code. The block in hex2dec works successfully for converting a single hexadecimal number to decimal number. It would be really helpful if someone could point out where I was going wrong in the use of array. Thanks.
DATA SEGMENT
NUM DW 1234H,9H,15H
RES DB 3*10 DUP ('$','$','$')
SIZE DB 3
DATA ENDS
CODE SEGMENT
ASSUME DS:DATA, CS:CODE
START:
MOV AX, DATA
MOV DS,AX
MOV DI,0
LOOP3:
MOV AX,NUM[DI]
LEA SI,RES[DI]
CALL HEX2DEC
LEA DX,RES[DI]
MOV AH,9
INT 21H
INC DI
CMP DI,3
JL LOOP3
MOV AH,4CH ; end program
INT 21H
CODE ENDS
HEX2DEC PROC NEAR
MOV CX,0
MOV BX,10
LOOP1:
MOV DX,0
DIV BX
ADD DL,30H
PUSH DX
INC CX
CMP AX,9
JG LOOP1
ADD AL,30H
MOV [SI],AL
LOOP2:
POP AX
INC SI
MOV [SI],AL
LOOP LOOP2
RET
HEX2DEC ENDP
END START
MOV AX,NUM[DI]
LEA SI,RES[DI]
LEA DX,RES[DI]
You are treating DI as an array index like we use in any of the high level languages. In assembly programming we only use displacements aka offsets in the array.
In your program, since the NUM array is composed of words, you need to give the DI register successively the values 0, 2, and 4.
ADD DI, 2
CMP DI, 6
JB LOOP3
Also it would be best to not treat the RES as an array. Just consider it a buffer and always use it from the start.
RES DB 10 DUP (0)
...
LEA SI, RES
CALL HEX2DEC
LEA DX, RES
A better version of HEX2DEC avoids the ugly prefixed "0" on the single digit numbers:
HEX2DEC PROC NEAR
XOR CX, CX <--- Same as MOV CX,0
MOV BX,10
LOOP1:
XOR DX, DX <--- Same as MOV DX,0
DIV BX
ADD DL, 30H
PUSH DX
INC CX
TEST AX, AX
JNZ LOOP1
LOOP2:
POP AX
MOV [SI], AL
INC SI
LOOP LOOP2
MOV AL, "$" <--- Add this to use DOS function 09h
MOV [SI], AL
RET
HEX2DEC ENDP
Related
%include "asm_io.inc"
segment .data
segment .bss
segment .text
global asm_main
asm_main:
enter 0,0
pusha
call read_int
push eax
call fak_rekursiv
add esp, 4
call print_int
call print_nl
popa
mov eax, 0
leave
ret
fak_rekursiv:
enter 4, 0
pusha
mov eax, [ebp + 8]
cmp eax, 0
je ergebnis_1
cmp eax, 1
je ergebnis_1
mov ebx, eax
dec ebx
mul ebx
push ebx
call fak_rekursiv
pop ebx
ergebnis:
mov [ebp - 4], eax
ergebnis_1:
mov [ebp - 4], dword 1
popa
mov eax, [ebp - 4]
leave
ret
I am learning to code on NASM and I was trying to understand recursion through using coding factorial but I got confused quickly.
How can I use Recursion in NASM to code factorial algorithm?
actually I have coded up factorial just for fun earlier. And now I have dug through my files to find that code :) here you go, but it is more like a pseudo-code which I only stepped through debugger.
factorial:
push eax
test eax, 07FFFFFFEh
jz .exit
dec eax
call factorial
mul dword [esp]
.exit:
pop edx
ret
put different values in eax and step through it in debugger.
Not too familiar with NASM, but here's a MASM solution which calls the factorial function recursively.
factorial.asm
.386
.model flat, stdcall
option casemap :none
includelib \masm32\lib\msvcrt.lib
printf PROTO C, :VARARG
.data
fmt db "%u! = %u", 13, 10, 0
.code
factorial proc
cmp eax, 0 ; Special-case to account for 0! = 1
je retone
cmp eax, 1
je retnow
push eax
dec eax
call factorial
pop edx
imul eax, edx ; eax = eax * edx
retnow:
ret
retone:
mov eax, 1
ret
factorial endp
main:
; Loop from 0 to 12 (max) factorial for 32-bit code.
mov ebx, 0
num:
mov eax, ebx
call factorial
invoke printf, OFFSET fmt, ebx, eax
inc ebx
cmp ebx,13
jne num
ret
end main
Displays all factorials from 0 to 12
I'm trying to design an algorithm in NASM which is supposed to compute the nth Fibonacci number. I wrote some code, but, when run, it outputs only 1 and I cannot understand why. My idea was to call Fibonacci for n-1 and for n-2, where the parameter n is stored within AX register, and the result is stored at BX.
%include "io.inc"
section .text
global CMAIN
CMAIN:
mov ebp, esp; for correct debugging
xor eax, eax
xor ebx, ebx
push word 12
call fibonacci
pop word [trash]
PRINT_UDEC 1, ax
ret
fibonacci: push ebp
mov ebp, esp
mov ax, [ebp + 8];se incarca ax cu parametrul primit prin stiva
cmp ax, 0
jne l1
mov bx, 0
jmp l3
l1: cmp ax, 1
jne l2
mov bx, 1
jmp l3
l2: sub ax, 2;n-2
push ax
call fibonacci
pop dx;resotre the stack
mov [ebp - 2], bx
mov ax, [ebp + 8];se incarca bx cu parametrul prinit prin stiva
sub ax, 1;n-1
push ax
call fibonacci
pop dx;restore the stack
add bx, [ebp - 2]
l3: mov esp, ebp
pop ebp
ret
section .data
trash dw 1
This is the format that I need:
F(3) = F(2) + F(1) =
F(2) = (F1) + F(0) =
F(1) = 1
F(0) = 1
F(2) = 1
F(1) = 1
F(3) = 2
and this is my code, how am I going to do to get the format I want?
Please give me a hint or something that may help, thank you. I just start learning assembly language.
I only know how to show the first line like f()= the answer, but don't know how to show the process.
.data
fib1 BYTE "f(",0
fib2 BYTE ") + f(",0
fib3 BYTE ") = ",0
intVal DWORD ?
main PROC
mov edx, OFFSET fib1 ;show f(intVal)=
call WriteString
mov edx, intVal
call WriteDec
mov edx, OFFSET fib3
call WriteString
mov ecx, intVal-1
push intVal
call fib
add esp, 4
call WriteDec ;show result
call crlf
mov edx, OFFSET msg5 ;show goodbye msg
call WriteString
mov edx, OFFSET username
call WriteString
exit
main ENDP
fib PROC c
add ecx, 1
push ebp
mov ebp, esp
sub esp,4
mov eax, [ebp+8] ;get value
cmp eax,2 ;if ((n=1)or(n=2))
je S4
cmp eax,1
je S4
dec eax ;do fib(n-1)+fib(n-2)
push eax ;fib(n-1)
call fib
mov [ebp-4], eax ;store first result
dec dword ptr [esp] ;(n-1) -> (n-2)
call fib
add esp,4 ;clear
add eax,[ebp-4] ;add result and stored first result
jmp Quit
S4:
mov eax,1 ;start from 1,1
Quit:
mov esp,ebp ;restore esp
pop ebp ;restore ebp
ret
fib ENDP
END main
The code needs to output a "newline" at the end of each line of output, which could be a carriage return (00dh) followed by a linefeed (00ah) or just a linefeed (00ah) depending on the system (I don't know the irvine setup).
The indented lines should be printed from within the fib function, which means you have to save (push/pop stack) any registers that the print functions use.
The fib function needs to print out a variable number of spaces depending on the level of recursion, based on the text, 2 spaces per level of recursion.
The fib function needs to handle an input of 0 and return 0.
Note that the number of recursive calls to the fib function will be 2 * fib(n) - 1, assuming fib checks for fib(0), fib(1), fib(2) (more if it doesn't check for fib(2) ), which would be 5.94 billion calls for fib(47) = 2971215073, the max value for 32 bit unsigned integers. You may want to limit inputs to something like fib(10) = 55 or fib(11) = 89 or fib(12) = 144.
In my 80x86 assembly program, I am trying to calculate the equation of
(((((2^0 + 2^1) * 2^2) + 2^3) * 2^4) + 2^5)...(2^n), where each even exponent is preceded by a multiplication and each odd exponent is preceded by a plus. I have code, but my result is continuously off from the desired result. When 5 is put in for n, the result should be 354, however I get 330.
Any and all advice will be appreciated.
.586
.model flat
include io.h
.stack 4096
.data
number dword ?
prompt byte "enter the power", 0
string byte 40 dup (?), 0
result byte 11 dup (?), 0
lbl_msg byte "answer", 0
bool dword ?
runtot dword ?
.code
_MainProc proc
input prompt, string, 40
atod string
push eax
call power
add esp, 4
dtoa result, eax
output lbl_msg, result
mov eax, 0
ret
_MainProc endp
power proc
push ebp
mov ebp, esp
push ecx
mov bool, 1 ;initial boolean value
mov eax, 1
mov runtot, 2 ;to keep a running total
mov ecx, [ebp + 8]
jecxz done
loop1:
add eax, eax ;power of 2
test bool, ecx ;test case for whether exp is odd/even
jnz oddexp ;if boolean is 1
add runtot, eax ;if boolean is 0
loop loop1
oddexp:
mov ebx, eax ;move eax to seperate register for multiplication
mov eax, runtot ;move existing total for multiplication
mul ebx ;multiplication of old eax to new eax/running total
loop loop1
done:
mov eax, runtot ;move final runtotal for print
pop ecx
pop ebp
ret
power endp
end
You're overcomplicating your code with static variables and branching.
These are powers of 2, you can (and should) just left-shift by n instead of actually constructing 2^n and using a mul instruction.
add eax,eax is the best way to multiply by 2 (aka left shift by 1), but it's not clear why you're doing that to the value in EAX at that point. It's either the multiply result (which you probably should have stored back into runtot after mul), or it's that left-shifted by 1 after an even iteration.
If you were trying to make a 2^i variable (with a strength reduction optimization to shift by 1 every iteration instead of shifting by i), then your bug is that you clobber EAX with mul, and its setup, in the oddexp block.
As Jester points out, if the first loop loop1 falls through, it will fall through into oddexp:. When you're doing loop tail duplication, make sure you consider where fall-through will go from each tail if the loop does end there.
There's also no point in having a static variable called bool which holds a 1, which you only use as an operand for test. That implies to human readers that the mask sometimes needs to change; test ecx,1 is a lot clearer as a way to check the low bit for zero / non-zero.
You also don't need static storage for runtot, just use a register (like EAX where you want the result eventually anyway). 32-bit x86 has 7 registers (not including the stack pointer).
This is how I'd do it. Untested, but I simplified a lot by unrolling by 2. Then the test for odd/even goes away because that alternating pattern is hard-coded into the loop structure.
We increment and compare/branch twice in the loop, so unrolling didn't get rid of the loop overhead, just changed one of the loop branches into an an if() break that can leave the loop from the middle.
This is not the most efficient way to write this; the increment and early-exit check in the middle of the loop could be optimized away by counting another counter down from n, and leaving the loop if there are less than 2 steps left. (Then sort it out in the epilogue)
;; UNTESTED
power proc ; fastcall calling convention: arg: ECX = unsigned int n
; clobbers: ECX, EDX
; returns: EAX
push ebx ; save a call-preserved register for scratch space
mov eax, 1 ; EAX = 2^0 running total / return value
test ecx,ecx
jz done
mov edx, ecx ; EDX = n
mov ecx, 1 ; ECX = i=1..n loop counter and shift count
loop1: ; do{ // unrolled by 2
; add 2^odd power
mov ebx, 1
shl ebx, cl ; 2^i ; xor ebx, ebx; bts ebx, ecx
add eax, ebx ; total += 2^i
inc ecx
cmp ecx, edx
jae done ; if (++i >= n) break;
; multiply by 2^even power
shl eax, cl ; total <<= i; // same as total *= (1<<i)
inc ecx ; ++i
cmp ecx, edx
jb loop1 ; }while(i<n);
done:
pop ebx
ret
I didn't check if the adding-odd-power step ever produces a carry into another bit. I think it doesn't, so it could be safe to implement it as bts eax, ecx (setting bit i). Effectively an OR instead of an ADD, but those are equivalent as long as the bit was previously cleared.
To make the asm look more like the source and avoid obscure instructions, I implemented 1<<i with shl to generate 2^i for total += 2^i, instead of a more-efficient-on-Intel xor ebx,ebx / bts ebx, ecx. (Variable-count shifts are 3 uops on Intel Sandybridge-family because of x86 flag-handling legacy baggage: flags have to be untouched if count=0). But that's worse on AMD Ryzen, where bts reg,reg is 2 uops but shl reg,cl is 1.
Update: i=3 does produce a carry when adding, so we can't OR or BTS the bit for that case. But optimizations are possible with more branching.
Using calc:
; define shiftadd_power(n) { local res=1; local i; for(i=1;i<=n;i++){ res+=1<<i; i++; if(i>n)break; res<<=i;} return res;}
shiftadd_power(n) defined
; base2(2)
; shiftadd_power(0)
1 /* 1 */
...
The first few outputs are:
n shiftadd(n) (base2)
0 1
1 11
2 1100
3 10100 ; 1100 + 1000 carries
4 101000000
5 101100000 ; 101000000 + 100000 set a bit that was previously 0
6 101100000000000
7 101100010000000 ; increasing amounts of trailing zero around the bit being flipped by ADD
Peeling the first 3 iterations would enable the BTS optimization, where you just set the bit instead of actually creating 2^n and adding.
Instead of just peeling them, we can just hard-code the starting point for i=3 for larger n, and optimize the code that figures out a return value for the n<3 case. I came up with a branchless formula for that based on right-shifting the 0b1100 bit-pattern by 3, 2, or 0.
Also note that for n>=18, the last shift count is strictly greater than half the width of the register, and the 2^i from odd i has no low bits. So only the last 1 or 2 iterations can affect the result. It boils down to either 1<<n for odd n, or 0 for even n. This simplifies to (n&1) << n.
For n=14..17, there are at most 2 bits set. Starting with result=0 and doing the last 3 or 4 iterations should be enough to get the correct total. In fact, for any n, we only need to do the last k iterations, where k is enough that the total shift count from even i is >= 32. Any bits set by earlier iterations are shifted out. (I didn't add a branch for this special case.)
;; UNTESTED
;; special cases for n<3, and for n>=18
;; enabling an optimization in the main loop (BTS instead of add)
;; funky overflow behaviour for n>31: large odd n gives 1<<(n%32) instead of 0
power_optimized proc
; fastcall calling convention: arg: ECX = unsigned int n <= 31
; clobbers: ECX, EDX
; returns: EAX
mov eax, 14h ; 0b10100 = power(3)
cmp ecx, 3
ja n_gt_3 ; goto main loop or fall through to hard-coded low n
je early_ret
;; n=0, 1, or 2 => 1, 3, 12 (0b1, 0b11, 0b1100)
mov eax, 0ch ; 0b1100 to be right-shifted by 3, 2, or 0
cmp ecx, 1 ; count=0,1,2 => CF,ZF,neither flag set
setbe cl ; count=0,1,2 => cl=1,1,0
adc cl, cl ; 3,2,0 (cl = cl+cl + (count<1) )
shr eax, cl
early_ret:
ret
large_n: ; odd n: result = 1<<n. even n: result = 0
mov eax, ecx
and eax, 1 ; n&1
shl eax, cl ; n>31 will wrap the shift count so this "fails"
ret ; if you need to return 0 for all n>31, add another check
n_gt_3:
;; eax = running total for i=3 already
cmp ecx, 18
jae large_n
mov edx, ecx ; EDX = n
mov ecx, 4 ; ECX = i=4..n loop counter and shift count
loop1: ; do{ // unrolled by 2
; multiply by 2^even power
shl eax, cl ; total <<= i; // same as total *= (1<<i)
inc edx
cmp ecx, edx
jae done ; if (++i >= n) break;
; add 2^odd power. i>3 so it won't already be set (thus no carry)
bts eax, edx ; total |= 1<<i;
inc ecx ; ++i
cmp ecx, edx
jb loop1 ; }while(i<n);
done:
ret
By using BTS to set a bit in EAX avoids needing an extra scratch register to construct 1<<i in, so we don't have to save/restore EBX. So that's a minor bonus saving.
Notice that this time the main loop is entered with i=4, which is even, instead of i=1. So I swapped the add vs. shift.
I still didn't get around to pulling the cmp/jae out of the middle of the loop. Something like lea edx, [ecx-2] instead of mov would set the loop-exit condition, but would require a check to not run the loop at all for i=4 or 5. For large-count throughput, many CPUs can sustain 1 taken + 1 not-taken branch every 2 clocks, not creating a worse bottleneck than the loop-carried dep chains (through eax and ecx). But branch-prediction will be different, and it uses more branch-order-buffer entries to record more possible roll-back / fast-recovery points.
Allright folks, let's hope this is an easy one: I need to access an array to achieve double-buffering (I use mode 13h) in 16-bit TASM. BUT: No matter if I use "OFFSET", "BYTE PTR [Array]", "BYTE PTR Array", or whatever I have tried already, the program reads/writes to the incorrect memory block, which is partly behind the actual start of the array.
Heres my (for now not really optimised and very messy) code:
.MODEL MEDIUM
.STACK
.DATA
XPos DW 0
YPos DB 0
Color DB 0
BoxX1 DW 0
BoxY1 DB 0
BoxX2 DW 0
BoxY2 DB 0
VPage DB 64010 DUP(0) ;TODO: Size *might* be incorrect.
PageSeg DW 0
.CODE
SetVGA13 PROC
MOV AX, 0013h ;Screen mode 13.
INT 10h ;Set screen mode to AX.
MOV AX, 0A000h ;Screen segment.
MOV ES, AX ;You can't affect segment registers
RET
ENDP
;-------DrawPixel---------------
; WORD XPos = x
; WORD YPos = y
; BYTE Color = colour
;-------------------------------
DrawPixel PROC
XOR AH, AH
MOV AL, [YPos]
MOV DX, 320
MUL DX
ADD AX, [XPos]
MOV DI, AX
MOV AL, [Color]
MOV ES, [PageSeg]
;ADD ES, DI
MOV ES:[DI],AL
;MOV ES:[DI],AL
RET
ENDP
DrawBox PROC
MOV CL, [BoxY1]
YLoop:
MOV BL, CL
PUSH CX
MOV CX, [BoxX1]
XLoop:
MOV [XPos], CX
MOV [YPos], BL
MOV [Color],CL
CALL DrawPixel
INC CX
CMP CX, [BoxX2]
JNZ XLoop
POP CX
INC CL
CMP CL, [BoxY2]
JNZ YLoop
RET
ENDP
WaitFrame PROC
PUSH DX
; Port #03DA contains VGA status
MOV DX, 03DAh
IN AL, DX
WaitRetrace:
; Bit 3 will be on if we're in retrace
TEST AL, 08h
JNZ WaitRetrace
EndRefresh:
IN AL, DX
TEST AL, 08h
JZ EndRefresh
POP DX
RET
ENDP
RestoreVideo PROC
; Return to text mode
MOV AX, 03h
INT 10h
RET
ENDP
ClearScreen PROC
XOR CX, CX
;MOV ES, [PageSeg]
ClearLoop:
MOV DI, CX
;MOV ES, [PageSeg]
MOV BX, OFFSET VPage
ADD BX, CX
MOV AL, [BX];VPage[DI];ES:[DI]
MOV [Color],AL
MOV AX, 0A000h
MOV ES, AX
MOV AL, [Color]
MOV ES:[DI],AL
INC CX
CMP CX, 64000
JNZ ClearLoop
RET
ENDP
Main:
;INITIALISE
MOV BX, OFFSET VPage
MOV [PageSeg],BX
CALL SetVGA13
;CALL MakePalette
MOV [BoxX1],33
MOV [BoxY1],33
MOV [BoxX2],99
MOV [BoxY2],99
;LOOP
GameLoop:
;DRAW
;CALL DrawBox
CALL ClearScreen
;CALL WaitFrame
;INPUT
MOV DX, 60h
IN AL, DX
CMP AL, 75
JNZ NotLeft
SUB [BoxX1],1
SUB [BoxX2],1
NotLeft:
IN AL, DX
CMP AL, 77
JNZ NotRight
ADD [BoxX1],1
ADD [BoxX2],1
NotRight:
CMP AL, 1
JNZ GameLoop
;END PROGRAM
Error:
;CALL ClearScreen
CALL RestoreVideo
MOV AH, 4Ch
INT 21h
END Main
This code shows a rainbow coloured box that you can move around with the left and right arrow keys,
;INITIALISE
MOV BX, OFFSET VPage
MOV [PageSeg],BX
That is my sad attempt to getbthe pointer to my buffer, but doesnt return the correct one
Sorry that my question was not done, i realised that when i got out of bed immediately for some reason.
Although this is not how I would code things, I'll offer up a couple of suggestions that may get you closer to resolving your problems.
When your executable loads the DS and ES registers originally point to the DOS PSP for your program. In your case you need to at least point DS to your DATA segment. The DATA segment that is filled in at run time by the DOS EXE loader can be referenced in your code by prefixing the segment name with an # (AT) symbol. So you can replace this code:
;INITIALISE
MOV BX, OFFSET VPage
MOV [PageSeg],BX
With this:
;INITIALISE
MOV BX, #DATA ; Set up DS with our program's DATA segment
MOV DS, BX
MOV [PageSeg],BX ; VPage is in DATA segment, move segment to PageSeg
In your DrawPixel code you'll need to add the VPage offset to DI. Replace this code:
XOR AH, AH
MOV AL, [YPos]
MOV DX, 320
MUL DX
ADD AX, [XPos]
MOV DI, AX
MOV AL, [Color]
MOV ES, [PageSeg]
MOV ES:[DI],AL
with:
XOR AH, AH
MOV AL, [YPos]
MOV DX, 320
MUL DX
ADD AX, [XPos]
MOV DI, AX
MOV AL, [Color]
MOV ES, [PageSeg]
ADD DI, OFFSET VPage ; We need to add VPage's offset
; from beginning of PageSeg
MOV ES:[DI],AL
Video mode 13h is 320x200x256 colors. The amount of video ram that is needed would be 320*200*1 = 64000. This could be changed from:
VPage DB 64010 DUP(0) ;TODO: Size *might* be incorrect.
to:
VPage DB 64000 DUP(0)
With these changes the program seems to display a rainbow box and moves left and right on the screen with the arrow keys.
There may be other bugs but I don't know what you were trying to achieve. This code could be simplified greatly. My changes were the minimal ones to work with the way you coded your program and make it somewhat functional.