include "asm.inc"
window 640,480,1
Function add_two(sys a, b) as sys
mov eax, a ' eax = a same as mov eax, [a]? NO!
add eax, b ' eax += b NO!
return eax
End Function
sub xAdd( byref a as sys, byref b as sys )
addr esi,a
addr edi,b
mov eax,[esi]
add eax,[edi]
end sub
sub AddMul( sys *a, b, c)
addr esi,a
mov eax,[esi]
add eax, b
imul eax, c
end sub
Text 10,10,24,add_two(100,200)
Text 10,26,24,xAdd(200,300)
Text 10,52,24,AddMul(200,300,2)
WaitKey
WinEnd
AddMul( sys *a, *b, *c) -> different
include "asm.inc"
window 640,480,1
sub AddMul( sys *a, *b, c )
addr esi,a
addr edi,b
mov eax,[esi]
mov ecx,[edi]
add eax, ecx
imul eax, c
end sub
sub AddDiv( sys *a, *b, *c )
xor edx,edx
addr esi,a
addr edi,b
mov eax,[esi]
mov ecx,[edi]
add eax, ecx
addr ecx,c
mov ecx,[ecx]
cmp ecx,0
jz gOut
idiv ecx
.gOut
end sub
Text 10,10,20, AddDiv(200,300,3)
WaitKey
WinEnd
$ filename "addmuldiv.exe"
'#include "$/inc/RTL32.inc"
#include "$/inc/console.inc"
function AddMul( int a, b, c )
addr esi,a ; esi=addr a
addr edi,b ; edi=addr b
mov eax,[esi] ; eax=[esi] =[a]
mov ecx,[edi] ; ecx=[edi] =[b]
add eax, ecx ; eax+=ecx
addr ecx,c ; ecx=addr c
imul eax,[ecx] ; eax i*= [ecx] ; =[c]
return eax
end function
function AddDiv( int a, b, c )
xor edx,edx ; edx=0 , division rest?
addr esi,a ; esi=addr a
addr edi,b ; edi=addr b
mov eax,[esi] ; eax=[esi] =[a]
mov ecx,[edi] ; ecx=[edi] =[b]
add eax, ecx ; eax+=ecx
addr ecx,c ; ecx=addr c
mov ecx,[ecx] ; ecx=[ecx] =[c]
cmp ecx,0 ; ecx ? 0
jz gOut ; if 0 .gOut
idiv ecx ; eax i\= ecx ; =[c]
return eax
.gOut
return 1/0 ; should be fixed
end function
print AddMul(200,300,3) : print cr
print AddDiv(200,300,3) : print cr
printl "Enter ..." : WaitKey
I can create the function with or without using the '*' pointer.
include "asm.inc"
window 320,240,1
function AddMul( int a, b, c ) as int
mov eax,a
add eax,b
imul eax,c
return eax
end function
function AddDiv( int a, b, c ) as int
mov ecx,c
cmp ecx,0
jz gOut
xor edx,edx
mov eax,a
add eax,b
idiv ecx
return eax
.gOut
end function
text 10,10,12,AddMul(10,10,10)
text 10,22,12,AddDiv(10,10, 4)
waitkey
winEnd
sub AddMul( int a, b, c )
mov eax,a
add eax,b
imul eax,c
end sub
sub AddDiv( int a, b, c )
mov ecx,c
cmp ecx,0
jz gOut
xor edx,edx
mov eax,a
add eax,b
idiv ecx
.gOut
end sub
#include "$/inc/console.inc"
include "asm.inc"
window 320,240,1
function AddMul( int a, b, c ) as int
mov eax,a
add eax,b
imul eax,c
return eax
end function
function AddDiv( int a, b, c ) as int
mov ecx,c
cmp ecx,0
jz gOut
xor edx,edx
mov eax,a
add eax,b
idiv ecx
return eax
.gOut
end function
text 10,10,12,AddMul(10,10,10)
text 10,22,12,AddDiv(10,10, 4)
text 10,40,12, "Enter ..."
print AddMul(10,10,10) & cr
print AddDiv(10,10, 4) & cr
waitkey
winEnd
#include "$/inc/console.inc"
sub AddMul( int a, b, c )
mov eax,a
add eax,b
imul eax,c
end sub
sub AddDiv( int a, b, c )
mov ecx,c
cmp ecx,0
jz gOut
xor edx,edx
mov eax,a
add eax,b
idiv ecx
.gOut
end sub
AddMul(10,10,10)
print eax & cr
AddDiv(10,10,4)
print eax & cr
printl "Enter ..." : waitkey
;
; file: math1.o2bas
; This program demonstrates how the integer multiplication and division
; instructions work.
;
#include "$/inc/console.inc"
;segment .data
;
; Output strings
;
zstring
prompt = "Enter a number: ",
square_msg = "Square of input is ",
cube_msg = "Cube of input is ",
cube25_msg = "Cube of input times 25 is ",
quot_msg = "Quotient of cube/100 is ",
rem_msg = "Remainder of cube/100 is ",
neg_msg = "The negation of the remainder is "
;segment .bss
;entry resd 1
int entry
print prompt
entry = val (rtrim ltrim input())
function do_math(int num) as string
int square, cube, cube25, quot, rem_, neg_
pushad ' save registers
mov eax, num
imul eax ; edx:eax = eax * eax
mov square, eax
mov ebx, eax ; save answer in ebx
imul ebx, [num] ; ebx *= [num]
mov eax, ebx
mov cube, eax
imul ecx, ebx, 25 ; ecx = ebx*25
mov eax, ecx
mov cube25, eax
mov eax, ebx
cdq ; initialize edx by sign extension
mov ecx, 100 ; can't divide by immediate value
idiv ecx ; edx:eax / ecx
mov ecx, eax ; save quotient into ecx
mov eax, ecx
mov quot, eax
mov eax, edx
mov rem_, eax
neg edx ; negate the remainder
mov eax, edx
mov neg_, eax
popad ' restore registers
' Output
string s = square_msg + square + cr +
cube_msg + cube + cr +
cube25_msg + cube25 + cr +
quot_msg + quot + cr +
rem_msg + rem_ + cr +
neg_msg + neg_ + cr
return s
end function
print do_math(entry)
printl "Enter ..." : waitkey
;
; file: math2.o2bas
; This program demonstrates how the integer multiplication and division
; instructions work.
;
#include "$/inc/console.inc"
;segment .data
;
; Output strings
;
zstring
prompt = "Enter a number: ",
square_msg = "Square of input is ",
cube_msg = "Cube of input is ",
cube25_msg = "Cube of input times 25 is ",
quot_msg = "Quotient of cube/100 is ",
rem_msg = "Remainder of cube/100 is ",
neg_msg = "The negation of the remainder is "
;segment .bss
int entry
int square, int cube, cube25, quot, rem_, neg_
print prompt
entry = val (rtrim ltrim input())
sub do_math(int num)
pushad ' save registers
mov eax, num
imul eax ; edx:eax = eax * eax
mov square, eax
mov esi, eax ; save answer in ebx
imul esi, [num] ; ebx *= [num]
mov eax, esi
mov cube, eax
imul ecx, esi, 25 ; ecx = ebx*25
mov eax, ecx
mov cube25, eax
mov eax, esi
cdq ; initialize edx by sign extension
mov ecx, 100 ; can't divide by immediate value
idiv ecx ; edx:eax / ecx
mov ecx, eax ; save quotient into ecx
mov eax, ecx
mov quot, eax
mov eax, edx
mov rem_, eax
neg edx ; negate the remainder
mov eax, edx
mov neg_, eax
popad ' restore registers
end sub
do_math(entry)
' Output
string s = square_msg & square & cr &
cube_msg & cube & cr &
cube25_msg & cube25 & cr &
quot_msg & quot & cr &
rem_msg & rem_ & cr &
neg_msg & neg_ & cr
print s
printl "Enter ..." : waitkey
include "asm.inc"
window 320,240,1
int data[6]
sub do_math(int num)
pushad ' save registers
mov eax, num
xor edx, edx
imul eax ; edx:eax = eax * eax
mov data[0], eax
mov edi, eax ; save answer inedi
imul edi, num ; edi *= [num]
mov eax,edi
mov data[1], eax
imul ecx,edi, 25 ; ecx =edi*25
mov data[2], ecx
mov eax,edi
mov ecx, 100 ; can't divide by immediate value
div ecx ; edx:eax / ecx
mov ecx, eax ; save quotient into ecx
mov data[3], ecx
mov eax, edx
mov data[4], eax
neg edx ; negate the remainder
mov data[5], edx
popad
end sub
do_math(15)
text 10, 20, 20, data[0]
text 10, 40, 20, data[1]
text 10, 60, 20, data[2]
text 10, 80, 20, data[3]
text 10,100, 20, data[4]
text 10,120, 20, data[5]
backcolor 0,0,255
text 10,160, 20, "OKAY!"
waitkey
winEnd
You have defined variables in global/static memory space, which are always referenced by the ebx register
The cure is to put this into a procedure and use local variables, which are referenced by ebp.
include "asm.inc"
window 640,480,1
sub test1
push ebx
mov ebx,200
mov eax,ebx
pop ebx
return eax
end sub
sub test2(sys a, b)
push ebx
mov ebx,a
add ebx,b
mov eax,ebx
pop ebx
return eax
end sub
text 20,10,12,str(test1) + " bananas"
waitkey
text 20,26,12, str(test2(50,50)) + " apples"
waitkey
winEnd
include "asm.inc"
window 400,300,1
'global
int data[6]
string outp <= {
"Square of input is ",
"Cube of input is ",
"Cube of input times 25 is ",
"Quotient of cube/100 is ",
"Remainder of cube/100 is ",
"The negation of the remainder is "
}
sub do_math(int num)
'local
int datas[6]
pushad ' save registers
mov eax, num
xor edx, edx
imul eax ; edx:eax = eax * eax
mov datas[0], eax
mov ebx, eax ; save answer in ebx
imul ebx, num ; ebx *= [num]
mov eax,ebx
mov datas[1], eax
imul ecx,ebx, 25 ; ecx =ebx*25
mov datas[2], ecx
mov eax,ebx
mov ecx, 100 ; can't divide by immediate value
div ecx ; edx:eax / ecx
mov ecx, eax ; save quotient into ecx
mov datas[3], ecx
mov eax, edx
mov datas[4], eax
neg edx ; negate the remainder
mov datas[5], edx
popad
'store global
for x=0 to 5
data[x]=datas[x]
next
end sub
do_math(15)
for x=0 to 5
text 10, (20+x*20) ,10, outp[x]
text 280, (20+x*20) ,10, data[x]
next
backcolor 0,0,255
text 10,160, 20, "OKAY!"
waitkey
winEnd
include "asm.inc"
window 640,480,1
function test1() as int
push ebx
mov ebx,200
mov eax,ebx
pop ebx
return eax
end function
function test2(sys a, b) as int
push ebx
mov ebx,a
add ebx,b
mov eax,ebx
pop ebx
return eax
end function
text 20,10,12, test1() + " bananas"
text 20,26,12, test2(50,50) & " apples"
waitkey
winEnd
;
; file: prime1.o2bas
; This program calculates prime numbers
;
; using assembly in OxygenBasic
#include "$/inc/console.inc"
;segment .data
zstring Message = "Find primes up to: "
;segment .bss
int Limit ; find primes up to this limit
int Guess ; the current guess for prime
;segment .text
; global _asm_main
_asm_main:
print Message
Limit = val (Input) : if Limit < 1 then goto end_while_limit
print "2" & chr(9) & "3" & chr(9) ; treat first two primes as special case
mov Guess, 5 ; Guess = 5;
while_limit: ; while ( Guess <= Limit )
mov eax, Guess
cmp eax, Limit
jnbe end_while_limit ; use jnbe since numbers are unsigned
mov ecx, 3 ; ecx is factor = 3;
while_factor:
mov eax, ecx
mul eax ; edx:eax = eax*eax
jo end_while_factor ; if answer won't fit in eax alone
cmp eax, Guess
jnb end_while_factor ; if !(factor*factor < guess)
mov eax, Guess
mov edx, 0
div ecx ; edx = edx:eax % ecx
cmp edx, 0
je end_while_factor ; if !(guess % factor != 0)
add ecx, 2 ; factor += 2;
jmp while_factor
end_while_factor:
je end_if ; if !(guess % factor != 0)
mov eax, Guess ; printf("%u\n")
pushad ' save registers
print eax & chr(9) ' do some basic
popad ' restore registers
end_if:
mov eax, Guess
add eax, 2
mov Guess, eax ; guess += 2
jmp while_limit
end_while_limit:
printl "Enter ..." : waitkey
'
'-----------------------------------
'TRACING EXECUTION OF ASSEMBLY CODE
'INSPECT REGISTERS AFTER INSTRUCTION
'===================================
include once "$\inc\console.inc"
'----------------
'DIAGNOSTIC MACROS
'================
def SHOW
pushad : mov a,%1 : printl "%1: " hex a : popad
end def
'
def MSG
pushad : printl %1 : popad
end def
'
def FLAGS
pushad : pushf : pushf : pop eax : mov a,eax : printl "Flag Register: " hex a : popf : popad
end def
'
def x
: pushad : pushf : call showregs : popf : popad :
end def
dim a
sub showregs()
dim as long v(9) at [ebp+8]
dim as string tab=chr 9
printl "
Registers:
EAX: " tab hex (v(9),8) "
ECX: " tab hex (v(8),8) "
EDX: " tab hex (v(7),8) "
EBX: " tab hex (v(6),8) "
ESP: " tab hex (v(5),8) "
EBP: " tab hex (v(4),8) "
ESI: " tab hex (v(3),8) "
EDI: " tab hex (v(2),8) "
EFLAGS:" tab hex (v(1),4) "
"
end sub
'waitkey
#include "$/inc/console.inc"
int num1=1008
int num2=128
function gcd (int a, b) as int
if a=0 and b=0 then
b=1
elseif b=0 then
b=a
elseif a != 0 then
while a != b
if a<b then
b-=a
else
a-=b
end if
wend
end if
return b
end function
printl "GCD of " num1 ", " num2 " = " gcd(num1,num2) & cr
; WATCOM C/C++ v10.0a output
function gcd1(int a, b) as int
push ebx ; o2 will need this
mov eax, a ; eax = a
mov edx, b ; edx = b
gcd:
mov ebx,eax
mov eax,edx
test ebx,ebx
jne L1
test edx,edx
jne L1
mov eax,1
ret
L1:
test eax,eax
jne L2
mov eax,ebx
ret
L2:
test ebx,ebx
je L5
L3:
cmp ebx,eax
je L5
jae L4
sub eax,ebx
jmp L3
L4:
sub ebx,eax
jmp L3
L5:
pop ebx ; o2 will need this
return eax
end function
printl "GCD of " num1 ", " num2 " = " gcd1(num1,num2) & cr
function gcd2(int a, b) as int
mov eax, a ; eax = a
mov edx, b ; edx = b
gcd:
neg eax
je L3
L1:
neg eax
xchg eax,edx
L2:
sub eax,edx
jg L2
jne L1
L3:
add eax,edx
jne L4
inc eax
L4:
return eax
end function
printl "GCD of " num1 ", " num2 " = " gcd2(num1,num2) & cr
printl "Enter ... " : waitkey
I think popcnt only becomes standard for all Pentiums in 2011, but I will include it together with lzcnt (leading zero count) in my imminent release.
SSE4.2 includes quite a few new SIMD instructions, unfortunately invalidating older processors.