News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

how to write code if right most bit is equal to 1?

Started by scooter4483, February 07, 2006, 09:06:17 PM

Previous topic - Next topic

scooter4483

Im not sure if im writing this code correctly.  I want to see if the right most bit in ebx is equal to 1.  If it is, it will jumb to a loop and do something.  Is this correct?

INCLUDE Irvine32.inc

.data

;---------------------------------------------------
.code


Main PROC
    mov ecx, 0
    mov eax, 380d
    mov ebx, 151d

A0: cmp ebx, 00000001h
    je A1

A1: mov ecx, eax
    add ecx, eax
    jmp A2

A2: shl eax, 1
    shr ebx, 1
    cmp ebx, 0
    jne A0

    call DumpRegs
    exit

Main ENDP

;---------------------------------------------------

END Main

thats all part of the code for my program.  the program is to multiply 32 bits in eax by 32 bits in ebx and store it in ecx.

ramguru

Hi, your code isn't very correct some jumps are just waste of code, more correct would be this:

    mov  ecx, 0
    mov  eax, 380
    mov  ebx, 151

A0:
    bt   ebx, 0 ; test lowest bit
    jnc  A2     ; if bit is zero jump to A2

A1:
    add ecx, eax

A2:
    shl eax, 1
    shr ebx, 1
    cmp ebx, 0
    jne A0

    ;....

MichaelW

scooter,

Another method:

test  ebx,1
jnz   rightmost_bit_is_1

TEST does a bitwise AND of the source and destination operands, and sets the flags according to the result. Unlike the AND instruction, TEST does not modify the destination operand. In this case the flag of interest is the Zero flag, which will be set if the AND operation produces a zero result, or cleared if the AND operation produces a non-zero result. The JNZ jumps if the zero flag is clear, indicating that the rightmost bit of EBX is one.

eschew obfuscation

scooter4483

thanks for the responses guys.  I modified my code but im pretty sure its not doing the multiplication correctly.  I also believe its putting the wrong number in eax and ebx always shows up as all zero's(dont know y), but i get some kind of result in ecx.  i just need a 32 bit eax unsigned number multiplied by a 32 bit unsigned number in ebx, and that result should be placed in ecx.  I can ignore the possibility of an overflow when the product exceeds 32 bits.  here it is:

Main PROC
    mov ecx, 0   ;ecx <- 0
    mov eax, 380   ;eax <- 380
    mov ebx, 151   ;ebx <- 151

A0:
    bt ebx, 0   ;testing the right most bit to 0
    jnc A2      ;if bit is zero jump to A2

A1:
    add ecx, eax   ;ecx <- ecx + eax

A2:
    shl eax, 1   ;shift eax left by 1 bit
    shr ebx, 1   ;shift ebx right by 1 bit
    cmp ebx, 0   ;compare to see if right most bit is 0
    jne A0      ;go to A0 if not equal to 0

    call DumpRegs
    exit

Ian_B

You haven't said on what test you want to do the multiply, and your code isn't doing a multiply. It looks like you're doing some strange sort of long multiplication, by repeated addition. This is bizarrely inefficient.

If all you really want to do is multiply EAX by EBX and have the low 32 bits of the result in ECX, ignoring any overflow in the high DWORD, and nothing else, which is what seems to be going on here, then the simplest and shortest and most correct code is:


    mov eax, 380   ;eax <- 380
    mov ebx, 151   ;ebx <- 151
    mul ebx        ;eax*ebx, 64-bit result in edx:eax
                   ;low 32 bits in eax, ignore high 32 bits in edx
    mov ecx, eax


No bit-testing required. MUL is a slow instruction, but WAY faster than doing long multiplication this way. Note that EDX is trashed by the MUL, so you will need to ensure that any critical value you were holding in it on entry to this code segment is in ECX instead, then you could XCHG it back into EDX before the MOV if necessary.

IanB

raymond

In your particular application, remember that shifting a register (either left or right) will set the CF flag according to the last bit shifted. You could simply move the "shr ebx,1" to the front and use the CF condition for jumping.

    mov ecx, 0   ;ecx <- 0
    mov eax, 380   ;eax <- 380
    mov ebx, 151   ;ebx <- 151

A0:
    shr ebx,1
    jnc A2      ;the right-most bit was not set if no carry

    add ecx, eax   ;ecx <- ecx + eax

A2:
    shl eax, 1   ;shift eax left by 1 bit
    test ebx,ebx   ;test to see if completed
    jne A0      ;go to A0 if not equal to 0


Raymond
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

Ian_B

#6
Ah, I now see you're trying to do this version of long multiplication as suggested in the Laboratory: http://www.masmforum.com/simple/index.php?topic=3704.msg27750#msg27750

The problem is that this is only fast as Eduardo suggests if you already know which bits are set in your multiplicands and "hard-write" the code to do the specific multiply with a specific number. The way you are testing individual bits and jumping here (some of which jumps will of course be mis-predicted), it will be much slower than the more general and simpler MUL for more than just a few binary digits, defeating the purpose.

IanB

scooter4483

I forgot to mention that i cannot use the "mul" statement.  The way im doing this is insufficient.  you are correct by saying that its not really doing multiplication.  i have to use shifting and adding statements to complete this multiplication.  what should i do?  thanks again.

Ian_B

Read through Eduardo's post carefully, the link I gave above: http://www.masmforum.com/simple/index.php?topic=3704.msg27750#msg27750

He gives an example of how it should work with a constant value (19). Trace through the procedure carefully and see how it should fit into your bit-testing algorithm, with Raymond's excellent optimisation suggestion above. Try dry runs with pen and paper for small constants, seeing how the registers change after every instruction, and you'll soon pin down what you are doing wrong and how to make sure you get the right result in the accumulator register.

Hint: don't confuse his use of EBX in that algorithm with your use, holding the multiplicand. You'll need three registers. You can load the value being multiplied into ECX first and operate just on that for simplicity, rather than setting ECX=0 and loading the value into EAX, which will free up EAX; but if you do the sum in EAX and move the final value into ECX at the end this will produce smaller code - all mathematical instructions using EAX as the first operand are one byte smaller in opcodes.

IanB

MusicalMike

When I wrote my first assembly program, it was a multiplication program, but what I did was something like this...

           mov eax, 5
           mov ebx, 5
startloop: add ecx, eax
           dec ebx
           jnz startloop


Yes, I do realize I should have used the mul instruction.

scooter4483

alright guys, after some reading and analyzing, this is what i got:

.data

x DWORD 6
y DWORD 5

;---------------------------------------------------
.code


Main PROC
    mov eax, x           ;eax <- x
    mov ebx, y           ;ebx <- y
    mov ecx, 0            ;ecx <- 0
    mov edx, 32          ;edx <- 32   

A0: shr ebx, 1           ;shift ebx right by 1 bit which puts the right most bit to carry flag
    jnc A1                  ;jump to A1 if right most bit if carry flag does not equal 1

    add ecx, eax          ;ecx <- ecx + eax

A1: shl eax, 1             ;shift eax left by 1 bit
    dec edx      ;edx <-edx - 1
    cmp edx, 0   ;compare the value of edx to 0
    jne A0

    call DumpRegs
    exit

Main ENDP

I 'hardwired' 6 and 5 to be my tests.  It gives me the correct result in ecx, but i have a small problem with it.  the 6 and 5 contents show up as all 0's when i call DumpRegs.  It should say EAX=00000006 and EBX=00000005.  Did i misswrite something?  thanks again.

ramguru

Hi again
I have no idea why you've rejected all previous suggestions (they were correct). If you want to track every iteration, you'll need insert something like this:

pusha
call DumpRegs
popa

but not at the end of algo (somewhere just after particular label). Keep in mind that after jne A0 ebx will be zero eax - very large...

scooter4483

thanks for the reply.  this is a beginners class and the didnt teach us pop and push so i cant use them.  my assignment was to hardwire a number to eax and ebx, multiply them using only shift and add instructions, then put the result in ecx.  i have done all those things, just my eax and ebx do not show the original values that i hardwired and i want that.  i understand that the code put them to all zeros after it has completed 32 iterations.  can anyone still help?  i looked at the link and those projects were similar but different than mine.  i cannot use the mul instruction as well in my code as told by my teacher.

ramguru

I think we need still more info. Do you need to show only original say x and y values. Maybe you need to show changed values in every iteration. And how DumpRegs looks (paste the code) ?

scooter4483

this what the teacher's instructions are:
Write an IA-32 assembly language program that initializes EAX and EBX to some values, multiplies them together with repeated shift/add operations assuming that these are unsigned binary integer codes (instruction MUL is not to be used) and stores the result in ECX. The contents of all three registers are then to be displayed on the screen in hex - using either DumpRegs or WriteHex. Initialize EAX and EBX to any values that you want, but we will test your code by changing these values to something else. Ignore the possibility of overflow when the product exceeds 32 bits