For some reason, when I run my program by executing it's .exe, it returns a wrong value, yet when I run through with debugger, it gives me the right value. What would cause such a thing?
Does it throw any exceptions ? Maybe you have ignored exceptions in your debugger and excecution continues normally. Or maybe it's a timing error.
EDIT: OK, just noticed that I am posting in the 16-bit forum ! My post is probably irrelevant, unless you postted in the wrong forum. Is your question regarding DOS ?
Hi,
Well, the last time that bit me, it was that DEBUG sets up
the values in the registers at startup differently than the DOS
program loader. Another time (on Windows XP) it was setting
the video mode differently (bad video drivers?).
HTH,
Steve N.
i would like to see the stretch of code that's giving you trouble
only a few things are different with the 16 bit debugger
console display - of course, the debugger has to be visible
console input - it also has to receive input
the psp - in debug, the process is actually a child of the debugger
that can also affect the environment table
command line tail - mainly, a shorter length limitation due to the debug command
breakpoints - if you are applying a breakpoint - try adding a nop instruction or 2 to break on
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
; Project 2 - Prooving NOR is universal for NOT, AND, and OR.
; Written By Edward Benn
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
; This program will go into various loops, crunching the values 0 - 255
; through the logical operators and their NOR equivelence into a software LFSR.
; By the end of the program, a byte code will be outputted from
; the LFSR and this will be compared to the instructor's and other students
; byte code outputted by their similar programs.
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
.model small
.stack 200h
.code
start:
; AL stores the current signature of the LFSR, BL contains the data to compress
; through the LFSR, and dl contains the loop counter.
main proc
NOTLOOP:
mov bl, dl ; moves the current count into bl
not bl ; Nots current count value
call lfsr ; performs the lfsr on bl
mov bl, dl ; value to pass to lfsr
or bl, dl ; nor step 1 (or with self)
not bl ; nor step 2 (negate the or)
call lfsr ; performs the lfsr on bh
inc dx ; increments the current count value
cmp dx, 1 ; number is max number to count to
jl NOTLOOP ; jump if number not met
mov cl, 8 ; loop 8 times(8 bits)
PRINTLOOP:
shl al, 1 ; shift al once
jc PRINT1 ; jump to print 1 if carry is set otherwise print 0
PRINT0:
push ax ; save ax
mov ah, 2 ; print character interupt code
mov dl, '0' ; 0 character to be printed
int 21h ; msdos interupt handler
jmp DONEPRINT ; done printing
PRINT1:
push ax ; save ax
mov ah, 2 ; print character interupt code
mov dl, '1' ; 1 character to be printed
int 21h ; msdos interupt handler
DONEPRINT:
pop ax ; get back the saved value
loop PRINTLOOP
mov ah, 4ch ; end program
int 21h
main endp
; Takes the value in the AL register and runs it through the LFSR with the current
; value in bl
lfsr proc
cmp al, 0 ; msb gets shifted
jl MSBSET ; Jumps if the MSB of AL is set.
shl al, 1
xor al, bl ; xors the signature with the data
jmp LFSRDONE ; lfsr operation is complete, jump to done
MSBSET:
shl al, 1
xor al, bl ; xors the signature with the data
xor al, 01100011b ; xors the signature with the lfsr feed back
LFSRDONE:
ret
lfsr endp
end main
I think whats giving me the trouble is the LFSR proc.
When I run it through the debugger, i get the correct output 01100010, which means the lfsr works.
But when i run the program, I get something completely different.
Your first code executed is "mov bl,dl" but DL isn't initialised. When you run it from debug, debug zeroes DX for you but DOS doesn't.
See also http://www.masm32.com/board/index.php?topic=10252.0
Wow thanks. I feel like such a n00b. :clap:
lfsr proc
cmp al, 0 ; msb gets shifted
jl MSBSET ; Jumps if the MSB of AL is set.
shl al, 1
xor al, bl ; xors the signature with the data
jmp LFSRDONE ; lfsr operation is complete, jump to done
MSBSET:
shl al, 1
xor al, bl ; xors the signature with the data
xor al, 01100011b ; xors the signature with the lfsr feed back
LFSRDONE:
ret
lfsr endp
Also, this subroutine is a little wacky.
When you write in assembler, your head has to always be looking for the most efficient way to accomplish
something, otherwise you are throwing out the main advantage of writing in assembler to begin with.
You will find this becomes more natural as you gain experience.
You will also find it very satisfying to know your head can manipulate bits like the CPU - lol.
This is the reason most of us that write assembly code prefer it over other languages.
It's not just the performance improvements, but the ego-boosting effects - lol.
One thing I see right away is that the CMP instruction is not needed
When you SHL on the AL register, bit 7 goes into the Carry Flag (CF).
You can use this fact to branch accordingly.
Also, you are duplicating the SHL and first XOR instructions.
Try to use the same one, regardless of the branch condition.
Another little flaw is that you JMP to a RET instruction - I usually avoid that, as you can replace the JMP with a RET.
The truth is, I always look at these simple pieces of code to see if I can eliminate branching altogether.
Conditional branches take a bit of time if the condition is true. Also, when the CPU branches to a new
address, it clears and re-loads the instruction queue, costing an additional penalty.
This can make code run faster, provided the math required does not outweigh the branch time.
I notice that the AH register is available for use (it has no assigned value in it that needs to be saved).
Here is a little trick you may enjoy. The CBW instruction takes the value in AL and sign-extends it into AX.
That means that if bit 7 of the AL register is 0, the CBW instruction will set AH to 00000000b.
If bit 7 of the AL register is 1, the CBW instruction will set AH to 11111111b.
We can use this to create a value in AH based on the condition of AL bit 7.
lfsr PROC
CBW
AND ah,01100011b
SHL al,1
XOR al,bl
XOR al,ah
RET
lfsr ENDP
The subroutine is now very small and fast. In fact, because it is only CALL'ed twice, it may
be advantageous to remove the CALL/RETurn altogether, and replace the CALL's with:
CBW
AND ah,01100011b
SHL al,1
XOR al,bl
XOR al,ah
CALL and RET also take alot of cylces to execute. mainly because they represent
memory accesses when the return address is pushed and popped on the stack.
There is also the instruction queue thing, again.
This code still has a little room for imporvement:
CBW
AND ah,00110001b
SHL ax,1
XOR al,bl
XOR al,ah
Here, we use bit 7 of the AL register to become the new bit 0 in the AH register.
I don't think this is much of an improvement in 32-bit world, but in 16-bit code,
this would make the code smaller by one byte, as SHL AX,1 is a single byte instruction.
SHL AL,1 is a two byte instruction. The optimization is still there if we use EAX.
In 32-bit code, I think the SHL EAX is one byte. I have yet to memorized the
32-bit instruction set - lol.
Both the NOTLOOP and the PRINTLOOP can be further optimized. I am going to leave that
to you, as 1) I want you to learn, and 2) I don't want to take all the fun out of it for you.
- Dave
Wow, that is really cool! It took me a few minutes to understand what was happening, but that is really clever!
Thanks for all the help guys!