Well, this program remember me assembly programming in dos. But i don't understand why i can't use a loop for the function. :eusa_snooty:
.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
.data
freqs dword 440,900,1000,1500,390,2150,700,1000,903,1009 ; In hertz.
times dword 1000,600,200,1020,190,500,720,1000,190,600 ; In milliseconds.
.code
begin proc
lea ebx,freqs
lea esi,times
push [esi]
push [ebx]
call Beep
inc esi ; Next dword...
inc esi
inc esi
inc esi
inc ebx
inc ebx
inc ebx
inc ebx
push [esi]
push [ebx]
call Beep
inc esi
inc esi
inc esi
inc esi
inc ebx
inc ebx
inc ebx
inc ebx
push [esi]
push [ebx]
call Beep
inc esi
inc esi
inc esi
inc esi
inc ebx
inc ebx
inc ebx
inc ebx
push [esi]
push [ebx]
call Beep
inc esi
inc esi
inc esi
inc esi
inc ebx
inc ebx
inc ebx
inc ebx
push [esi]
push [ebx]
call Beep
inc esi
inc esi
inc esi
inc esi
inc ebx
inc ebx
inc ebx
inc ebx
push [esi]
push [ebx]
call Beep
inc esi
inc esi
inc esi
inc esi
inc ebx
inc ebx
inc ebx
inc ebx
push [esi]
push [ebx]
call Beep
inc esi
inc esi
inc esi
inc esi
inc ebx
inc ebx
inc ebx
inc ebx
push [esi]
push [ebx]
call Beep
inc esi
inc esi
inc esi
inc esi
inc ebx
inc ebx
inc ebx
inc ebx
push [esi]
push [ebx]
call Beep
inc esi
inc esi
inc esi
inc esi
inc ebx
inc ebx
inc ebx
inc ebx
push [esi]
push [ebx]
call Beep
push 0
call ExitProcess
begin endp
end begin
But is really fun! :biggrin:
any reason to not use "add esi, 5"?
Quote from: LordAdef on May 13, 2017, 10:47:31 AM
any reason to not use "add esi, 5"?
Well, at least before, inc was a shorter instruction, than was add...
Also, esi should be incremented by 4 not 5. This is because you have to address to increasing memory locations. Remember that each memory location in Intel's micro is a byte . And 4 bytes make a double word (dword).
The confusion may be in that the first memory address loaded to esi is like the "zero" position. So you increment esi by 4 and you obtain the next dword and so on.
inc is one byte
add esi, 127 is three bytes
add esi, 128 needs five bytes
In the unlikely case that...
- you need an add esi, 4
- esi points to a valid memory location
- you couldn't care less about eax
- and speed doesn't matter:
lodsd needs one byte 8)
Edited for poasm:.386
.model flat,stdcall
option casemap:none
includelib kernel32.lib
;extern ExitProcess:proc
;extern Beep:proc
.data
freqs dword 440,900,1000,1500,390,2150,700,1000,903,1009 ; In hertz.
times dword 1000,600,200,1020,190,500,720,1000,190,600 ; In milliseconds.
.code
WinMainCRTStartup proc C
; push ebx
lea esi,freqs
lea edi,times
mov ebx, 10
@@: push dword ptr[edi]
push dword ptr[esi]
call Beep@8
add esi, 4
add edi, 4
dec ebx
test ebx,ebx
jnz @B
push 0
call ExitProcess@4
WinMainCRTStartup endp
end ;WinMainCRTStartup
QuoteAlso, esi should be incremented by 4 not 5.
Sorry, I didn´t count the incs correctly.
As TWell also suggested:
Quoteadd esi, 4
add edi, 4
You should do fine with that and it´s clearer.
There´s a big debate about "inc eax" vs "add eax, 1" in terms of speed. But in your case I wouldn´t think twice and use add. That´s why I asked.
What if you needed to add 50?
One other thing to be checked, and I might be wrong: beep does not seem to work for every system anymore.
Quote from: felipe on May 13, 2017, 07:06:14 AM
But is really fun! :biggrin:
A bit noisy.
Listen to this:
.686
.XMM
.MODEL FLAT, STDCALL
option casemap:none
option dllimport:<kernel32.dll>
ExitProcess PROTO :DWORD
Beep PROTO :DWORD,:DWORD
Sleep PROTO :DWORD
E1 EQU 329.63
F1 EQU 349.23
G1 EQU 392.0
A1 EQU 440.0
B1 EQU 493.88
C2 EQU 523.25
D2 EQU 587.33
E2 EQU 659.26
Q EQU 222.0
H EQU 444.0
W EQU 889.0
WZ EQU 1778.0
.data
FREQ DD G1,G1,E1,F1,G1,A1,B1,C2,A1,B1,G1,F1
DD G1,D2,E2,C2,D2,B1,C2,B1,A1,G1,F1,E1,G1
DD C2,C2,C2,C2,B1,D2,D2,C2,B1,A1,A1,G1,B1,B1,B1,B1,A1,G1,G1,G1,A1,G1
DD F1,E1
DURAC DD H,WZ,Q,Q,H,H,Q,H,Q,H,H,WZ
DD H,WZ,Q,Q,H,H,Q,H,Q,H,H,WZ,W
DD Q,H,Q,H,Q,Q,H,Q,H,H,H,WZ,Q,H,Q,H,H,H,Q,H,H,Q
DD Q,WZ
num_notes dd 48
NOTE_DUR dd 0.8
.code
playMusic proc uses ecx freq:real4, duration:real4
; play = duration*NOTE_DUR;
movss xmm0, duration
movss xmm1, xmm0 ; save
mulss xmm0, NOTE_DUR
cvtss2si eax, xmm0 ; convert to int
;off = duration - play;
subss xmm1, xmm0
cvtss2si ebx, xmm1 ; convert to int
movss xmm2, freq
cvtss2si edx, xmm2 ; convert to int
;Beep(freq, play);
INVOKE Beep, edx, eax
;Sleep(off);
INVOKE Sleep, ebx
ret
playMusic endp
start proc
mov ecx, num_notes
mov esi, offset FREQ
mov edi, offset DURAC
@loop:
INVOKE playMusic, real4 ptr [esi], real4 ptr [edi]
add esi, TYPE FREQ
add edi, TYPE DURAC
loop @loop
invoke ExitProcess, 0
start endp
end start
Quote from: aw27 on May 13, 2017, 06:57:36 PM
Quote from: felipe on May 13, 2017, 07:06:14 AM
But is really fun! :biggrin:
A bit noisy.
Listen to this:
.686
.XMM
.MODEL FLAT, STDCALL
option casemap:none
option dllimport:<kernel32.dll>
ExitProcess PROTO :DWORD
Beep PROTO :DWORD,:DWORD
Sleep PROTO :DWORD
E1 EQU 329.63
F1 EQU 349.23
G1 EQU 392.0
A1 EQU 440.0
B1 EQU 493.88
C2 EQU 523.25
D2 EQU 587.33
E2 EQU 659.26
Q EQU 222.0
H EQU 444.0
W EQU 889.0
WZ EQU 1778.0
.data
FREQ DD G1,G1,E1,F1,G1,A1,B1,C2,A1,B1,G1,F1
DD G1,D2,E2,C2,D2,B1,C2,B1,A1,G1,F1,E1,G1
DD C2,C2,C2,C2,B1,D2,D2,C2,B1,A1,A1,G1,B1,B1,B1,B1,A1,G1,G1,G1,A1,G1
DD F1,E1
DURAC DD H,WZ,Q,Q,H,H,Q,H,Q,H,H,WZ
DD H,WZ,Q,Q,H,H,Q,H,Q,H,H,WZ,W
DD Q,H,Q,H,Q,Q,H,Q,H,H,H,WZ,Q,H,Q,H,H,H,Q,H,H,Q
DD Q,WZ
num_notes dd 48
NOTE_DUR dd 0.8
.code
playMusic proc uses ecx freq:real4, duration:real4
; play = duration*NOTE_DUR;
movss xmm0, duration
movss xmm1, xmm0 ; save
mulss xmm0, NOTE_DUR
cvtss2si eax, xmm0 ; convert to int
;off = duration - play;
subss xmm1, xmm0
cvtss2si ebx, xmm1 ; convert to int
movss xmm2, freq
cvtss2si edx, xmm2 ; convert to int
;Beep(freq, play);
INVOKE Beep, edx, eax
;Sleep(off);
INVOKE Sleep, ebx
ret
playMusic endp
start proc
mov ecx, num_notes
mov esi, offset FREQ
mov edi, offset DURAC
@loop:
INVOKE playMusic, real4 ptr [esi], real4 ptr [edi]
add esi, TYPE FREQ
add edi, TYPE DURAC
loop @loop
invoke ExitProcess, 0
start endp
end start
error A2008: syntax error : dllimport
\test.asm(47) : error A2006: undefined symbol : xmm0
\test.asm(48) : error A2006: undefined symbol : xmm1
\test.asm(49) : error A2006: undefined symbol : xmm0
\test.asm(50) : error A2006: undefined symbol : xmm0
\test.asm(53) : error A2006: undefined symbol : xmm1
\test.asm(54) : error A2006: undefined symbol : xmm1
\test.asm(56) : error A2006: undefined symbol : xmm2
\test.asm(57) : error A2006: undefined symbol : xmm2
:(
Quote from: TWell on May 13, 2017, 05:40:04 PM
Edited for poasm:.386
.model flat,stdcall
option casemap:none
includelib kernel32.lib
;extern ExitProcess:proc
;extern Beep:proc
.data
freqs dword 440,900,1000,1500,390,2150,700,1000,903,1009 ; In hertz.
times dword 1000,600,200,1020,190,500,720,1000,190,600 ; In milliseconds.
.code
WinMainCRTStartup proc C
; push ebx
lea esi,freqs
lea edi,times
mov ebx, 10
@@: push dword ptr[edi]
push dword ptr[esi]
call Beep@8
add esi, 4
add edi, 4
dec ebx
test ebx,ebx
jnz @B
push 0
call ExitProcess@4
WinMainCRTStartup endp
end ;WinMainCRTStartup
This worked fine in masm after removing @4 and @8. :t
Quote from: felipe on May 13, 2017, 09:44:22 PM
error A2008: syntax error : dllimport
\test.asm(47) : error A2006: undefined symbol : xmm0
\test.asm(48) : error A2006: undefined symbol : xmm1
\test.asm(49) : error A2006: undefined symbol : xmm0
\test.asm(50) : error A2006: undefined symbol : xmm0
\test.asm(53) : error A2006: undefined symbol : xmm1
\test.asm(54) : error A2006: undefined symbol : xmm1
\test.asm(56) : error A2006: undefined symbol : xmm2
\test.asm(57) : error A2006: undefined symbol : xmm2
:(
For Masm, instead of
option dllimport:<kernel32.dll>
use
includelib kernel32.lib
If it does not compile, delete the Masm.exe or ML.exe you have, probably from last century, and look for a more recent Masm, they come free with Visual Studio Community Edition.
I already did this: "includelib kernel32.lib"
So this should be the problem:
"If it does not compile, delete the Masm.exe or ML.exe you have, probably from last century, and look for a more recent Masm, they come free with Visual Studio Community Edition. "
Thanks :icon14:
.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
.data
freqs dword 440,900,1000,1500,390,2150,700,1000,903,1009 ; In hertz.
times dword 1000,600,200,1020,190,500,720,1000,190,600 ; In milliseconds.
.code
begin proc
mov ebx,10
lea edi,freqs
lea esi,times
play_all:
push [esi]
push [edi]
inc esi
inc esi
inc esi
inc esi
inc edi
inc edi
inc edi
inc edi
call Beep
dec ebx
test ebx,ebx
jnz play_all
push 0
call ExitProcess
begin endp
end begin
Thanks Twell. :icon14: But, what's wrong with the other registers, such as ecx, why they give me troubles? For example: The same algo, but using ecx instead ebx and using the loop instruction. Assembly and link good, the program runs, but has a bad end. :(
Quote from: felipe on May 13, 2017, 10:32:51 PM
But, what's wrong with the other registers, such as ecx
eax, edx and ecx are volatile, i.e they will be used within the Beep call without preserving their state on entry. ebx is perserved. This is what the stdcall specification says!
If you understood my example you could see that I took all the care about that but knowing what the API calls would do. I knew that the API call would preserve the esi and edi registers, I knew they will not preserve the ecx registers so I saved it on entry to the playMusic routine and I knew they will preserve the ebx register so I was sure the value will not be changed by the Beep call and could use it in Sleep call.
"delete the Masm.exe or ML.exe you have, probably from last century, and look for a more recent Masm, they come free with Visual Studio Community Edition. "
I already have the vs community 2015. So i did a backup of ml and link, then i replaced this files with those of vs crap. Then i did have to add mspdb140.dll from vc in the bin directory of masm and after that worked fine. :t
Good job, sounds like bossa nova i think. :bgrin:
Quote from: felipe on May 13, 2017, 10:50:32 PM
Then i did have to add mspdb140.dll from vc in the bin directory of masm and after that worked fine. :t
It replaces the 19 years old crap you have there mspdb50.dll
Quote
Good job, sounds like bossa nova i think. :bgrin:
La Paloma
Quote from: aw27 on May 13, 2017, 11:06:04 PMIt replaces the 19 years old crap you have there mspdb50.dll
And let's your code crash on older machines :bgrin:
Quote from: jj2007 on May 14, 2017, 01:25:00 AM
Quote from: aw27 on May 13, 2017, 11:06:04 PMIt replaces the 19 years old crap you have there mspdb50.dll
And let's your code crash on older machines :bgrin:
True, no more waivers for bad code - let it crash everything. :greenclp:
Quote from: aw27 on May 13, 2017, 10:48:32 PM
Quote from: felipe on May 13, 2017, 10:32:51 PM
But, what's wrong with the other registers, such as ecx
eax, edx and ecx are volatile, i.e they will be used within the Beep call without preserving their state on entry. ebx is perserved. This is what the stdcall specification says!
I didn't see this reply before. Thanks a lot. :icon14:
I wasn't aware of this. I only knew that the parameters are passed (in this convention) in opposite order, that the function called cleans the stack and that the return value is in eax.
Thanks again, :t. I have to keep learning. :greenclp:
Quote from: aw27 on May 13, 2017, 10:48:32 PM
If you understood my example you could see that I took all the care about that but knowing what the API calls would do.
Now i know what the USES directive does. :icon_mrgreen: