Hello everyone,
Please allow me to introduce myself and tell why and how I am here today.
.me
I´m Alex (LordAdef is an old avatar I can´t get rid of...it´s my Macro :greensml:). I´m Brazilian and am 45. I am a music composer and music producer. As everyone around my age, I started programming BASIC, qBASIC etc.... Afterwards I had some quick experience with C. I quit programming when classical music came in and took all my time. Then it came Bachelor Degree and Masters Degree. After things got quieter, the addiction hit me back and I made several programs in a language called Lingo (native of the former Macromedia Director). It was crap, but I had some fun.
So, as an introduction, I´m not a professional and not a student under supervision, I´m only brave :D
.why?
Recently, addiction hit me again... I need to bloody program!! I need to bloody program!!
Options for serious stuff, not toys, were down to:
C++ -> absolutely not
C or Assembly -> ?????????
C came out being the one... thousands of links tutorials, videos in youtube and so forth..
Assembly was once again left behind
.Then
VStudio is free, soon I finished a quite nice game prototype all in pure C, using the SDL libs. Great!!!
Meanwhile, I couldn´t resist and was reading all I could find about asm on the internet. Believe me, I know all the tuts in youtube. I read a couple of books either.
.aFeedback
Asm is not "Not for the faint of heart" (now a legendary line for me)... finding your way around it today without supervision IS...
I would love if some of you top guys could someday write a "Get started"... Assembly deserve a complete and up to date one. For me was like coming into a jungle... it still is!!!
.foundYou
So I decided for MASM. It was an easy choice really. I didn´t know (as most of us noobs) the HLL capabilities. And them I MASM32.
At this point I already know most of you by name(Hutch, Gunther, jj, etc..)! I´ve been reading this forum for a long long time. GREAT PEOPLE!!!
Hutch, I think you are a legend! your work and efforts brought me to Assembly
.Enough
I could be writing nonstop about this Saga for ages.
I don´t know anything, I´m just starting. I won´t fill the forum with question after question (I read the rules :eusa_dance:). But if anyone could provide me with some help, this would be great.
Thank you for MASM32 existence
ps: edited typos
Welcome to the Forum, Alex - you are at the right place here :icon14:
Hi Alex,
Good to see you here. We will lead you astray with the intent of seeing you produce small fast code. The line "not for the faint of heart" is in fact true, assembler programming is hard to learn, brutally intolerant and will bite you on the arse for the slightest mistake but it teaches you to do things the right way the first time, don't take crappy short cuts and to write reliable code. It can be a rough ride at first but once you get it, its a ton of fun and you get high quality results from it.
Welcome Alex.
Andy
Quote from: jj2007 on January 22, 2017, 10:18:15 AM
Welcome to the Forum, Alex - you are at the right place here :icon14:
Thank you JJ! It took me a while to join. By the way, I downloaded MasmBasic too. In fact, I followed your tips and tricks page when downloaded masm32!
Quote from: hutch-- on January 22, 2017, 01:36:37 PM
Hi Alex,
Good to see you here. We will lead you astray with the intent of seeing you produce small fast code. The line "not for the faint of heart" is in fact true, assembler programming is hard to learn, brutally intolerant and will bite you on the arse for the slightest mistake but it teaches you to do things the right way the first time, don't take crappy short cuts and to write reliable code. It can be a rough ride at first but once you get it, its a ton of fun and you get high quality results from it.
I´m feeling at home already by the warm welcome!
I guess we find the right place when you find people with common interests. I could be doing my C thing and make my life easier. But you know.... Assembly looks so more obvious to me... and I always forget the bloody semicolons at the end of lines... Assembly don`t have them :greenclp:
So I know the homework... I bought the new Rolling Stones album and am ready to crack on the masm32 help files.
I also am reading the whole Campus forum. It´s something the Newbies should do before asking the same questions. It´s greatly informative since you guys already answered many of the same questions.
I installed masm32 in a different computer from the VStudio one. It´s a clean start. I´m fine with no syntax highlighting, but still need to get used not to have the integrated debugger as in VS. For that I downloaded the Olly one as JJ suggested
Quote from: Magnum on January 23, 2017, 03:05:46 PM
Welcome Alex.
Andy
Thanks Andy!
For how long do we have to keep answering these verification questions?
not for long, its only to deter spammers.
hello LordAdef, welcome irmão
[<o>]
Hi, and welcome to the forum :biggrin:
If you are just setting up your workshop, most people here will not recommend VS because it's too big and bloated.
Hardcore assemblers go with something simpler like Top Gun editor (included in MASM32). As someone who already tried Radasm and Winasm, I gave my vote to EasyCode if you want 32/64 bits, WYSIWYG and syntax highlighting in a breeze; EC's help file is worth its weight in gold by itself. :lol:
Happy coding :t
Quote from: mineiro on January 24, 2017, 02:00:38 AM
hello LordAdef, welcome irmão
[<o>]
Hey Mineiro, I already knew there was a fellow country man here. Obviously, by your name and the Raul Seixas´ quote you use in your posts :t
Thanks for stopping by and say hello.
I´m from Rio de Janeiro, and I guess you are in Minas, right?
Quote from: AssemblyChallenge on January 25, 2017, 08:34:21 AM
Hi, and welcome to the forum :biggrin:
If you are just setting up your workshop, most people here will not recommend VS because it's too big and bloated.
Hardcore assemblers go with something simpler like Top Gun editor (included in MASM32). As someone who already tried Radasm and Winasm, I gave my vote to EasyCode if you want 32/64 bits, WYSIWYG and syntax highlighting in a breeze; EC's help file is worth its weight in gold by itself. :lol:
Happy coding :t
Hi AssemblyChallenge, thanks for the advises. I´m aware of the VS thing. In fact, I installed masm32 in a different computer (faaaaar away from VS). To be quite honest, I still miss the integrated debugger of VS, but I´m getting used to the new tools (and getting to know then)
I´m playing with the qEditor and JJ´s RichMasm. But today I downloaded EasyCode too.
I´m too impressed with how friendly this community is! I´m spending a great deal of time skinning through old threads and checking out. Amazing.
Guys,
qEditor, demo 5 (numbers.asm):
It doesn´t compile. I´m pretty sure it´s not recognizing the "include \masm32\macros\macros.asm".
I commented all the includes and included the masm32rt.inc instead and all worked fine
Quoteinclude \masm32\include\masm32rt.inc
comment #
include \masm32\include\windows.inc ; always first
include \masm32\macros\macros.asm ; MASM support macros
; -----------------------------------------------------------------
; include files that have MASM format prototypes for function calls
; -----------------------------------------------------------------
include \masm32\include\masm32.inc
include \masm32\include\gdi32.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
; ------------------------------------------------
; Library files that have definitions for function
; exports and tested reliable prebuilt code.
; ------------------------------------------------
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
#
I´d like to know what´s happening
Quote from: LordAdef on January 26, 2017, 11:19:40 AM
qEditor, demo 5 (numbers.asm):
It doesn´t compile. I´m pretty sure it´s not recognizing the "include \masm32\macros\macros.asm".
...
I´d like to know what´s happening
So you get an assembler error. Where did you find numbers.asm? Which error, which line? Same error in RichMasm?
The original file was missing the include and library for MSVCRT. Including the "masm32rt.inc" file solves the problem as it does contain msvcrt. The original file was written in 2004 and something has changed since.
If you wanted to use the older form in the original, it would look like this.
; -----------------------------------------------------------------
; include files that have MASM format prototypes for function calls
; -----------------------------------------------------------------
include \masm32\include\masm32.inc
include \masm32\include\gdi32.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\msvcrt.inc
; ------------------------------------------------
; Library files that have definitions for function
; exports and tested reliable prebuilt code.
; ------------------------------------------------
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\msvcrt.lib
JJ:
QuoteSo you get an assembler error. Where did you find numbers.asm? Which error, which line? Same error in RichMasm?
Numbers.asm is the demo 5 in masm32 tutorials. Hutch already pin pointed the issue. masm32rt is the way to go!
Hutch
QuoteIf you wanted to use the older form in the original, it would look like this.
Thanks! I´m fine with the modern way. I bloody love masm32rt.inc!!!!
Sorry to bother you guys!
Quote from: LordAdef on January 26, 2017, 12:03:12 PM
Numbers.asm is the demo 5 in masm32 tutorials.
Glad you solved it :t
Tmp_File.asm(73) : Error A2159: INVOKE requires prototype for procedure
sval(2)[macros.asm]
sval MACRO lpstring
IFNDEF __UNICODE__
invoke crt_atol,reparg(lpstring)
ELSE
invoke crt__wtol,reparg(lpstring)
ENDIF
EXITM <eax>
ENDM
Hi guys,
So.....I´ve been doing my homework... and I wrote this small (and useless) program. My first!
I wanted to do something very simple, so that I could accomplish and show it to you gurus.
It DOES work!!
Your comments will be invaluable, from every point of view... Not just in ways to optimize it but also how it´s commented and presented.
It was all coded in qEditor and I didn´t need debugging for this one.
Please, be kind, I´m actually quite proud of my small little beast :biggrin:
Any comment will be of great help.
Cheers
Alex
ps: .zip file attached
Hi Alex,
Nice effect, it works like a charm :t
Little suggestions:
mov esi, offset Ln1
; xor eax, eax ; will be immediately overwritten
mov eax, SIZEOF Ln1 ; no Ssize needed ;Get item based on LoopC index
mul LoopC
add esi, eax ;ADD size => next line
print esi, 13, 10 ;PRINT next
inc LoopC ;increment Loop
; xor edx, edx ;Get =>LoopC mod LINES
mov eax, LoopC
cdq ; sets edx to zero but is one byte shorter than xor edx, edx
For assigning small numbers (-128 ... +127) to registers, there is the m2m macro:
m2m eax, 123
mov eax, 123
Same result but m2m is 2 bytes shorter. Do not use it in a speed-critical innermost loop (i.e. one with >1Mio iterations).
m2m means "memory to memory", it does a
push 123
pop eax
which is not exactly mem to mem but it works :P
You can eliminate one jump, but attention to the logic:
.ELSE
inc LineC
We all love eliminating jumps 8)
Thank you so much JJ!!!!
I made all the changes, and also managed to eliminate the jump:
Quote.IF LineC==LINES ;AFTER lines are printed
inc LineOffSet ;increment LineOffSet and make it modular
xor edx, edx
mov eax, LineOffSet
mov ebx, LINES
div ebx
mov LoopC, edx ;add LineOffSet to LoopC, so to increment the starting line
mov LineC, 0 ;Set to 0 instead of 1, to eliminate the jump
loc 0,0 ;Return console cursor to line 0
.ENDIF
inc LineC
I´m thinking that maybe I could eliminate LineC. I´m using LoopC for modulus and LineC to keep track of my Lines. Maybe, I could increment a LOCAL variable (or a safe register) based on LoopC and throw LineC away. Not sure if it will take any considerable load though.
Yes, I eliminated LineC and am using edi for the job. I guess I get some boost from this.
Any place you think I should use m2m in the code?
Quote from: LordAdef on January 30, 2017, 09:50:05 PMAny place you think I should use m2m in the code?
m2m eax, SIZEOF Ln1
But really, this is just a habit of old assembler programmers who like optimising ;)
Other example:
and LineC, 0 ;reset LineC
3 bytes shorter.
(some may argue that this is a) slower and b) useless, because there is more than enough RAM around. Truth is that it's no good in a tight innermost loop; but anywhere else it is good, because the instruction cache is very small, and it may make a difference if a whole loop fits into that cache because you saved a byte here and there)
Thanks JJ, ALL comments well noted and learned!
Just a comment on the macro "m2m". The rough distinction is you use m2m in high level code to make it more compact and easier to read. In any code that is time critical it is faster to use a register.
mov reg, memory2
mov memory1, reg
Its common from the 16 bit DOS era for byte pinching here and there but we have very different hardware and OS conditions these days and you generally chase speed before size as the size difference is trivial where the speed difference is worth having. Speed comes from picking the right algorithm, coding the algorithm carefully with the right choice of instructions, minimising the number of branches and keeping memory access to a minimum (memory is slow in comparison to registers).
This stuff comes with practice and the CLOCK, when speed matters, your only real friend is the CLOCK. Its like in motor racing, when the flag drops the bullshit stops.
Thanks Hutch! I see what you and JJ mean. I incorporated "m2m" and "and" in my codes. I imagine these principles get more valid when you have larger codes, when saving bytes here and there will count (as pointed out by JJ).
My first prog was reading the lines as variables from the data section. I thought it would be nice if it read the data from file.
So I coded my prog2. This time I made a procedure, since I intend to integrate this LoadFile proc into the other code.
I used m2m and AND, following JJ´s observation.
It was a nice exercise. I had to deal with things I haven´t touched before.
I am also learning that Assembly is a severe father! It took me half an hour to realize I had written "map1.text" instead of "map1.txt". I felt a complete idiot, since I almost got nuts trying to understand what was wrong...
I sending to the proc an offset of my string (the file name).
I´m using:
QuotepLoad proc, string:LPSTR
I tried DWORD and it worked too. I found about LPSTR searching our forum, and it was the recommended one. Would you clarify me on this?
Once again, thank you for all this support.
Alex
ps: I may not touch any C for the next decade.... Assembly is beautiful :eusa_boohoo:
Quote from: hutch-- on January 31, 2017, 10:47:46 AMIn any code that is time critical it is faster to use a register ... your only real friend is the CLOCK
Correct. Just to illustrate this:
include \masm32\MasmBasic\MasmBasic.inc ; download (http://masm32.com/board/index.php?topic=94.0)
Init
loopcount=100000000
PrintCpu 0
Print Str$("\nTimings for %i loops:\n", loopcount)
REPEAT 5
NanoTimer()
mov ecx, loopcount
.Repeat
mov eax, 127
dec ecx
.Until Zero?
Print Str$("%i ms for mov\n", NanoTimer(ms))
NanoTimer()
mov ecx, loopcount
.Repeat
m2m eax, 127
dec ecx
.Until Zero?
Print Str$("%i ms for m2m\n\n", NanoTimer(ms))
ENDM
EndOfCodeResults:
Intel(R) Core(TM) i5-2450M CPU @ 2.50GHz
Timings for 100000000 loops:
35 ms for mov
69 ms for m2m
34 ms for mov
69 ms for m2m
35 ms for mov
103 ms for m2m
35 ms for mov
70 ms for m2m
34 ms for mov
68 ms for m2m
In short: You need ONE-HUNDRED MILLION iterations to demonstrate that m2m is "slower" than mov.
QuoteIn short: You need ONE-HUNDRED MILLION iterations to demonstrate that m2m is "slower" than mov
Incredible! Noted
Also you just taught me how to profile my code... I was missing this JJ. This may be my entry point to masmBasic
Quote from: LordAdef on February 01, 2017, 07:44:37 PMI found about LPSTR searching our forum, and it was the recommended one. Would you clarify me on this?
Windows.inc:
LPSTR typedef DWORDIt's exactly the same type. 90% of all code in assembler deals with dwords, the rest being REAL4/8/10, byte and word variables.
Now what is right here? Raise the question and find yourself in an ideological war between the old "hey, it's 4 bytes, isn't it?" fraction and those who come from C/C++ and see their world crumbling if you "mistype" LPSTR as DWORD :P
Btw if there is a real problem, the assembler will shout at you, at least in the 32-bit world. So don't worry.
Re LoadFile: Works like a charm, well done :t
You over-optimise a little bit, though. Once your code is running, it's always nice to see it through the eyes of a debugger...
pLoad proc, string:LPSTR ;=============== Load, Parse file & fill array ========
int 3 ;make Olly stop here when hitting F9
and ebx,0 ;loop
xor ebx, ebx ;shorter way of zeroing a register
m2m esi, InputFile(string) ;Source file (ecx ret. size)
m2m edi, offset Map ;Destination
mov edi, offset Map ;shorter - offsets are big numbers ;-)
@@:
m2m ecx, cWidth ;shorter, cWidth is a small number
mov ecx, cWidth ;lenght of line
rep movsb ;copy
inc edi ;Skips 0s
inc ebx ;loop
cmp ebx, cHeight
jb @B
free esi ;closes it
ret
pLoad endp
00401032 ³. CC int3
00401033 ³. 83E3 00 and ebx, 00000000
00401036 ³. 33DB xor ebx, ebx
00401038 ³. 68 14224000 push offset 00402214 ; ÚArg3 = LoadFile.402214
0040103D ³. 68 10224000 push offset 00402210 ; ³Arg2 = LoadFile.402210
00401042 ³. FF75 08 push dword ptr [ebp+8] ; ³Arg1 => [Arg1]
00401045 ³. E8 C6000000 call 00401110 ; ÀLoadFile.00401110
0040104A ³. 8B0D 14224000 mov ecx, [402214]
00401050 ³. A1 10224000 mov eax, [402210]
00401055 ³. 50 push eax ; m2m esi, InputFile(string)
00401056 ³. 5E pop esi
00401057 ³. 68 00204000 push offset 00402000
0040105C ³. 5F pop edi
0040105D ³. BF 00204000 mov edi, offset 00402000
00401062 ³> 6A 0A Úpush 0A
00401064 ³. 59 ³pop ecx
00401065 ³. B9 0A000000 ³mov ecx, 0A
0040106A ³. F3:A4 ³rep movsb
Note, for example, that
m2m esi, InputFile(string) results in a
push eax, pop esi sequence;
mov eax, esi has the same size, so no need to optimise here. In fact, the only valid cases for m2m are 1. memory-to-memory transfers between variables (that's why the macro was written) and 2. mov reg32, small integer (-128...+127).
A hard-core optimiser, btw, would save one byte by using
xchg InputFile(string), esi:
00401045 ³. E8 C6000000 call 00401110 ; ÀLoadFile.00401110, read_disk_file
0040104A ³. 8B0D 14224000 mov ecx, [402214]
00401050 ³. A1 10224000 mov eax, [402210]
00401055 ³. 96 xchg eax, esi ; m2m esi, InputFile(string)
Don't make this a habit, though: You risk losing a lot of time chasing single bytes instead of concentrating on good code.
For better understand the disassembly, here an excerpt from \masm32\macros\macros.asm:
InputFileA MACRO lpFile
...
invoke read_disk_file,reparg(lpFile),
ADDR ipf@__@mem@__@PtrA,
ADDR ipf@__file__@lenA
mov ecx, ipf@__file__@lenA ;; file length returned in ECX
mov eax, ipf@__@mem@__@PtrA ;; address of memory returned in EAX
EXITM <eax>
ENDM
Thanks,
I´ll have a closer and careful look at the debugger.
QuoteDon't make this a habit, though: You risk losing a lot of time chasing single bytes instead of concentrating on good code.
Ok. But it´s always a good habit to learn from the beginning I think. The most precious thing I´m learning from you is the "mindset". If you don´t learn this, one will never become a good Assembly programmer.
Update, prog3
Prog3, ScrollingFromFile, uses 2 procedures: pLoad (my loading code from prog2) and pConsoleEngine (adapted from my prog1, it generates the scrolling effect on the console)
1. It loads the file, parse it and fills the array.
2. I put all the engine code into the procedure and made its variables as LOCALS, to encapsulate a bit (right design choice?)
3. I turned all constants into High Caps to be more consistent
4. Made the changes based on JJ´s comments
5. The lenght (cWIDTH) and number of lines (cHEIGHT) are still hard coded. I might work on this next, although my array declaration asks for constants:
Quote.const
cWIDTH EQU 20 ;num of Chars in a line
cHEIGHT EQU 60 ;num of Lines
.data
Map db cHEIGHT dup(cWIDTH dup(?),0) ;Main array, adds 0 for termination
Filename db "Map1.txt",0
4. When running the prog, we need to manually adjust the size of the console window to fit the current 60 lines. I didn´t bothered to search about this for now
5. Last but not least, I made a small Homage to JJ in the scrolling text :greenclp:
I might soon be porting this onto a Windows frame.
There is a context for how and why some of the older fellas still do some things the way it was done over 25 years ago. With pre-486 processors (1990) you actually DID count cycles and with very slow 8088 and slightly later hardware, packing code into smaller layouts by instruction choice was a viable form of optimisation for writing memory image COM files in MS-DOS. The problem was that this changed with the 486DX which introduced the concept of a pipeline where the action switched to "scheduling" instructions through that pipeline in the most efficient order.
It also entailed abandoning some of the old instructions because while they still worked, the internal guts of the processors ran faster if you stuck to simpler preferred instruction set that Intel published. Packing instructions in the right order meant the processor did not have to stop and wait for a result which caused a stall and this became more important with multiple pipeline later processors. Some of this varied with different processors but the general direction from the 486 era onwards was to use simpler instructions in the right order, minimising branching and reducing the number of memory operations.
You can pick up bad habits like using out of date instructions (xchg, movsb/w/d/q and stosb/w/d/q without the REP prefix) and various others but it will come at the price of producing sub standard code that is often not as fast as junky high level code. You chase reduced instruction counts where you can by removing redundancies in your code but do not fall for just chasing code sized reduction as it does not produce useful results and often slows your code down.
Quote from: hutch-- on February 02, 2017, 03:12:24 PMYou can pick up bad habits like using out of date instructions (xchg, movsb/w/d/q and stosb/w/d/q without the REP prefix)
Nothing of what Hutch writes is entirely wrong, but the context matters a lot. Inside a tight loop that runs a Million times, one should indeed be careful. In all other cases,
xchg eax, reg32 saves a byte at
no additional cost, and
stosd is a wonderful instruction for storing a bunch of handles into their global variables. And there are numerous other examples where old instructions can be the right ones.
There are also the incredibly old
inc and
dec instructions, which trigger every now and then an exchange of religious views on the speed difference to
add and
sub, see here (http://masm32.com/board/index.php?topic=5900.0) for a recent example, or here (http://www.masmforum.com/board/index.php?topic=4662.msg34741#msg34741) for a less recent one (
why is "add" faster than "inc", April 2006).
If you want to see super-fast super-modern "junky high level code" in action, install Visual Studio Community (https://www.google.com/search?num=20&newwindow=1&safe=off&site=&source=hp&q=Visual+Studio+Community+slow). The good news, it's
free, but warning, your hardware is probably too old for such modern code, and it may take a while until you see the editor in front of you 8)
:biggrin:
And when you add up all of the size reductions gained by picking old slow instructions, it still does not add one 512 byte section to an executable. Start down the slippery slope of writing garbage and you will end up with garbage. :P
Quote from: hutch-- on February 02, 2017, 10:43:02 PMAnd when you add up all of the size reductions gained by picking old slow instructions
These instructions are old, but they don't slow down your code as long as you don't do really stupid things like squeezing them into a tight loop. On the contrary, every saved byte that does not end up in the instruction cache may indeed make your code faster.
:biggrin:
> may indeed make your code faster.
This is indeed a big IF when code cache performance is easily testable. Loop unrolling is a perfect mechanism to see where the performance limit is. Keep increasing the level of unrolling until the code goes not faster then keep unrolling the loop code until it gets slower and you will find the cache limit of the particular processor you are using. Test it across a range of hardware and you will start to get averages and the code you put into production will hit somewhere in the middle of cache performance.
The assumption that code sized effects are cumulative across an entire application is unsound, it is always local to where the code occurs. With modern hardware, close range code size almost exclusively does not matter where instruction choice will bite you on that arse if you use old DOS era junk. Develop the habit of tolerating garbage to save a few bytes here and there and you will end up producing garbage.
REPEAT 1000
Quote from: jj2007 on February 03, 2017, 02:54:05 AMThese instructions are old, but they don't slow down your code as long as you don't do really stupid things like squeezing them into a tight loop.
Quote from: hutch-- on February 03, 2017, 06:42:04 AMDevelop the habit of tolerating garbage to save a few bytes here and there and you will end up producing garbage.
ENDM
I think that people use assembler to optimize code.
Those who want to generate garbage to waste CPU resources, there is already Java for that.
Just couple lines of code and lot of memory and CPU cycles wasted.
:biggrin:
> REPEAT 1000
Repetition does not make substandard code work any better. Write garbage, get garbage. :P
Tim,
You can write poor code in any language, assembler is certainly not immune from producing slow sloppy code as many have found out.
Quote from: hutch-- on February 03, 2017, 09:02:10 AMWrite garbage, get garbage.
Did I ever insult you, Hutch?
:biggrin:
> Did I ever insult you, Hutch?
Regularly but its useful for folks learning to understand that there is a wide variety of opinion in coding techniques and the only one that matters is their own. :P
Update: prog4, the scrolling ported to windows.
I use Iczelion´s code for the Window and changed it to my taste.
Run it and move you mouse over the window to trigger the scroll.
The rendering code is within the Window message: .ELSEIF uMsg==WM_PAINT:
Quote.ELSEIF uMsg==WM_PAINT
invoke BeginPaint,hWnd, ADDR ps
mov hdc,eax
;================================ FONT ======================================
invoke CreateFont,16,0,0,0,400,0,0,0,OEM_CHARSET,\
OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,\
DEFAULT_QUALITY,DEFAULT_PITCH or FF_SCRIPT,\
ADDR FontName
invoke SelectObject, hdc, eax
mov hfont,eax
RGB 255,255,255
invoke SetTextColor,hdc,eax
RGB 50,50,50
invoke SetBkColor, hdc,eax
;================================ RENDERER ===================================
xor edi, edi ;Loop
mov esi, 1 ;esi= y coord of line 1
@@:
mov hitpoint.x, 300
m2m hitpoint.y, esi
;--- MOD ArrayLineOffset & Multiply ---
mov eax, ArrayLineOffset ;MOD ArrayLineOffset
mov ebx, cHEIGHT
cdq
div ebx
mov ArrayLineOffset, edx ;MOD value
mov eax, ArrayLineOffset
mov ebx, cWIDTH
mul ebx ;get array. eax= array offset (index)
invoke TextOut,hdc,hitpoint.x,hitpoint.y,ADDR Map+[eax], cWIDTH
add esi, 15 ;(tYPos)
inc ArrayLineOffset
inc edi ;loop increment
cmp edi, cHEIGHT
jb @B
invoke SelectObject,hdc, hfont ;closes font
invoke EndPaint,hWnd, ADDR ps ;End Paint
.ELSEIF uMsg==WM_DESTROY
invoke PostQuitMessage,NULL
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
:icon_confused: The prog has a problem though :icon_confused::
It starts running with 3.150 bytes, but the memory usage keeps getting higher and higher. Around 10.000 something happens... (same result if I loose the font code)
ps: Guys, I just completed my first week in MASM!
CreateFont would ideally be placed in some other part of the program, at startup, initialization routine etc, where the font handle is saved.
invoke CreateFont,16,0,0,0,400,0,0,0,OEM_CHARSET,\
OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,\
DEFAULT_QUALITY,DEFAULT_PITCH or FF_SCRIPT,\
ADDR FontName
mov hfont,eax
Can be moved to WM_INITDIALOG or something else.
The old font object is probably still being leaked when selecting and clearing it i suspect. I would have an hOldFont handle when using the SelectObject and restore once finished with it.
Something like:
Invoke SelectObject, hdc, hFont
mov hOldFont, eax
.
.
. do some stuff with text and font
.
.
.
Invoke SelectObject, hdc, hOldFont
Of course there could be a resource leak elsewhere or something else ive forgotten.
You are totally right! I'll move the font code to another place. I thought of that but didn't implemented. Even I will need more than one font.
I commented the font code and the leak persists
Just checked, it´s the font that´s leaking memory.
I moved the code into WM_INITDIALOG, and also to WM_CREATE, but nothing happens in both places
Follow the zip code with prog4 fixed. No more memory leak, it´s steady at 3.132 bytes.
It was the font thing
Good you have chased it down. :t
Quote from: hutch-- on February 05, 2017, 02:25:02 PM
Good you have chased it down. :t
Thanks!
By the way, I´m doing these progs in increment to learn and improve piece by piece.
The idea is to make a re-creation of the Atari game "River Raid", in ascii. This scrolling experiment is the idea for the game´s map rolling down.
An update! And a world of questions....
So, still testing the waters... I made a temporary map of something closer to a River Raid level map.
The thing runs and stops when we reach the end of it.
There´s no game logic at all. I´m still trying things out.
I´m really on my own here, any help would be really appreciated!
I´m using the Window´s loop as my game loop.
I need a timer to control my game flow/speed. This was the best I could come out with. Any better solution?
Quoteinvoke GetTickCount ;Timer
mov tMyTick, eax
.WHILE TRUE
invoke GetMessage, ADDR msg,NULL,0,0
.BREAK .IF (!eax)
invoke DispatchMessage, ADDR msg
;=========================================================
;=============== MY GAME LOOP HERE!!!! ===================
;=========================================================
; My calling points here
; call pGame proc
; call pColisionDetection
tTimer: ;Controlling speed
invoke GetTickCount
sub eax, tMyTick
cmp eax, 40 ;waits x ticks
jb tTimer
invoke GetTickCount
mov tMyTick, eax
invoke InvalidateRect,hwnd, ADDR mapRect, FALSE ;All done, render:
.ENDW
As an ascii game, I´m stuck with the WM_PAINT Msg, so I´m leaving all my rendering there.
(Man is that green A on screen. It´s gonna be the player´s boat.. or whatever)
Quote.ELSEIF uMsg==WM_PAINT
;invoke GetTickCount ;******** timing
;mov DebugTick, eax ;******** timing
invoke BeginPaint,hWnd, ADDR ps
mov hdc,eax
;===== BK MAP ===============
;============================
invoke SelectObject, hdc, Font1 ;select font
RGB 255,255,255
invoke SetTextColor,hdc, eax
RGB 50,50,50
invoke SetBkColor, hdc, eax
invoke SetBkMode, hdc, OPAQUE
;render map
;(cHEIGHT-ArrayLineOffset)*cWIDTH...
;...ArrayLineOffset increases until = cHEIGHT
mov eax, cHEIGHT ;(avoiding interdependancy)
mov ebx, cWIDTH
mov esi, offset Map
sub eax, ArrayLineOffset
mov edi, 80 ;loop counter
mul ebx ;eax= lineOffset addr
mov hitpoint.x, 80 ;loc x
add esi, eax ;initial address to textout
mov hitpoint.y, 1 ;loc of line 1
@@:
invoke TextOut,hdc,hitpoint.x,hitpoint.y, ADDR [esi], ebx
add esi, ebx ;next line
add hitpoint.y, 10 ;y pos inc
dec edi ;loop counter
jnz @B
;invoke GetTickCount ;******** timing **********
;sub eax, DebugTick ;******** timing **********
;print str$(eax),13,10 ;******** timing **********
;============================
;===== MAN ==================
;============================
invoke SelectObject, hdc, Font2 ;select font
RGB 0,255,0
invoke SetTextColor,hdc, eax
RGB 50,50,50
invoke SetBkColor, hdc, eax
invoke SetBkMode, hdc, TRANSPARENT
invoke TextOut,hdc,0,600, ADDR Man, cWIDTH
;=====================================================================
;===== End of Map? ===================================================
mov eax, cHEIGHT ;if it´s 0 then we reached
cmp eax, ArrayLineOffset ; the top of the map
jz LevelEnd
inc ArrayLineOffset
jmp PaintEnds
LevelEnd: ;==Reached the end of Map. Level is over
invoke EndPaint,hWnd, ADDR ps ;End Paint
ret
PaintEnds:
invoke EndPaint,hWnd, ADDR ps ;End Paint
.I need this map to be really optimized.
Am I too bad? How can I make it faster .I tried to time my code with the commented GetTickCount and related. I´m sure it´s not actually working as it should.
Help...pleaseLastly, this experiment has a major flaw: Every time one moves the mouse, Windows stops scrolling to do its things. I need to find a way to make it non stop.
Honestly, I don´t know howCheers, Alex
I would be inclined to use a timer as the loop you are using to get the delay is causing the problem with the mouse. I am rusty in this area but a multi-media timer used to have far better resolution. What processor are you using ? This may effect the thread timings depending on the core count.
Quote from: hutch-- on February 08, 2017, 06:09:39 PM
I would be inclined to use a timer as the loop you are using to get the delay is causing the problem with the mouse. I am rusty in this area but a multi-media timer used to have far better resolution. What processor are you using ? This may effect the thread timings depending on the core count.
Hi Hutch,
Win7 Professional 64bits
Intel Core i7-4790
Hutch, the mouse is not delaying, it´s actually halting the WM_PAINT.
OK, hardware is fast enough with enough threads, when you set up a timer it is placed in another thread by the OS so you app should not have any lag in it.
Quote from: hutch-- on February 08, 2017, 07:28:57 PM
OK, hardware is fast enough with enough threads, when you set up a timer it is placed in another thread by the OS so you app should not have any lag in it.
Ok, I see what I can do!
GOT IT!
At least for now that will do. I realised I was doing something stupid create an unnecessary loop hook in my timer. I´m using an .If.
Quoteinclude \masm32\include\winmm.inc
includelib \masm32\lib\winmm.lib
...
It´s a timeGetTime in winmm.lib
Quoteinvoke timeGetTime
sub eax, MyTime
.IF eax>=80
invoke InvalidateRect,hwnd, ADDR mapRect, FALSE ;All done, render:
invoke timeGetTime ;retrieve next Starting time
mov MyTime, eax
.ENDIF
ps: Included the missing Level1.txt in the zip file
:t
This works fine on my Win10 64 bit. :biggrin:
Interstingly I have not seen ascii animation for years. Once long ago I watched an ascii art version of star wars and you could follow what was happening.
Quote from: hutch-- on February 10, 2017, 04:57:37 AM
Interstingly I have not seen ascii animation for years. Once long ago I watched an ascii art version of star wars and you could follow what was happening.
Thanks Hutch. Yes, ascii animation is fun but has been out of the loop for a while. I thought it would be a nice project as a beginner not to have to deal with more complex graphics, an ascii little game could be acomplishable. In fact, it could even turn into a nice tutorial for newbies like me...
I will keep doing this project as I am, step by step, without jumping ahead of myself. Every little step teaches me something new, and that´s the goal.
A benchmark test between:
Quote.WHILE TRUE
invoke PeekMessage, ADDR msg, NULL, 0, 0, PM_REMOVE
.IF (eax != 0) ......
(using timeGetTime)
and
Quote.WHILE TRUE
invoke GetMessage, ADDR msg, NULL, 0, 0; , PM_REMOVE
.IF (eax != 0)......
using WM_TIMER
The 2 versions in the zip file.
timeGetTime vs TIMER (millisecs):
at 10:
timeGetTime 31-32 CPU: 11.88
TIMER 31-32 CPU: 11.66
at 40
timeGetTime 15-16 rare peaks: 31 CPU: 11.60
TIMER 15-16 rare peaks: 31 CPU: 6.85
at 80:
timeGetTime 15-16 rare peaks: 31 CPU: 11.88
TIMER 31-47 rare peaks: 16 CPU: 5.08
at 120:
timeGetTime 15-16 rare peaks: 31 CPU: 11.88
TIMER 31-47 CPU: 4.40
So, my map file was about 89.999 bytes and it´s too big, since I will need many.
I decided to optmize it.
With the code bellow I manage to turn the Level1.txt (89.999) into an array of 8.488 bytes.
It´s an array of pairs. Each pair reads "charValue", "lenght". So @@@@@@@@@@ gives 64,10.
The code works, but I have a stupid question I admit I couldn´t find the answer:
I wanted to put charValue into "bh", and the sum of chars into "bl". I thought if I pass "bx" to the array I had the right order. But it´s not... I manually inverted bh, bl, for bl, bh to have it right... What am I missing?
BX -> BH, BL in this order, right?
I´m getting the other way around: BX-> BL, BH
QuoteThis should be in bh:
mov bl, [esi + edi] ; the value for the new char in bl----------- Fills bl
This should be in bl:
add bh, 1 ; it´s the same char, add sum in bh ------------------- sum in bh
Here I pass them to the array:
mov [eax], bx ; send the 2 bytes to dest array
Here is the complete procedure:
start:
invoke pLoad, offset Filename
inkey
invoke ExitProcess, eax
pLoad proc, string:DWORD
LOCAL tLen :DWORD
LOCAL MapIndex:DWORD
mov esi, InputFile(string) ; esi is source
mov tLen, ecx ; lenght of file in tLen (returns in ecx)
new:
xor ebx, ebx ; bl= char bh= char count
mov bl, [esi + edi] ; the value for the new char in bl----------- Fills bl
mov bh, 1 ; sum acumulator to 1
same:
add edi, 1 ; add counter
cmp edi, tLen ; end of file?
jz done ; we are done
cmp bl, [esi + edi] ; comp char in bl with current
jnz notEqual
;it´s an equal char
add bh, 1 ; it´s the same char, add sum in bh ------------------- sum in bh
jmp same ; jumps 'same'
notEqual: ; it´s a new sequence of the same new char
mov eax, offset Map
add eax, MapIndex
mov [eax], bx ; send the 2 bytes to dest array
add MapIndex, 2 ; update dest array index
jmp new ; 'new' sets the new char to bl
done:
free esi
xor edi, edi ; edi is index
printf ("Original size= %d ", tLen)
print " ",13,10
printf ("New size= %d ", MapIndex)
print " ",13,10
ret
pLoad endp
end start
JJ, this f11 function in RichMasm is Fantastic!!
hello LordAdef;
"little endian" and big endian is about your question.
mov [eax], bx ; send the 2 bytes (grouped) to dest array
on line above, if bx == 0102h , when you store this value from register to memory their order changes because you're dealing with word, so will be stored on memory as 0201h.
Just check this, after store a word,dword, qword on memory, get only one byte from that address instead of more than 1 byte and you will see the point.
mov [eax],12345678h ;a double word, 4 bytes group stored on address pointed by eax register
So, on memory that will look like
[rax] pointed address contents == 78563412h
offtopic: Oh yes LordAdef, I'm from Minas Gerais, yes, this slogan is about Rauzlito. Good to see brothers here trying the Latim language of computers.
Hi,
X86 is little endian, which means when you store a register to
memory, its apparent byte order becomes reversed. For the BX
register, you can use the old DOS DEBUG to see what/how that
happens. Or there are endless tutorials and discussions on endian-
ness fun out and about the web.
HTH,
Steve N.
P.S. While typing I was scooped (someone beat me to answer.).
SRN
A couple of things here, Steve is right about the byte order of a 32 bit register if you think of 4 bytes labeled 0123, in memory they are stored as 3210 and this is a characteristic of x86 hardware. It catches people who are learning because byte data like text is stored left to right but numbers are stored in reverse order. In 32 bit you can access the two lowest bytes with AL and AH but for a long time Intel have advised against using the high byte and it 64 bit you cannot access it at all.
If you can manage it, do all of your BYTE register reads and writes in the low byte register AL/BL/CL etc .... It takes a bit more organisation so you don't run out of registers but a lesson I have learnt writing 64 bit algos, the ones I wrote properly in win32 easily converted to Win64 where the odd one or two were pigs that had to be rewritten because you could not access the high byte directly. You can still indirectly access any of the last 3 bytes of a DWORD by using rotates or shifts but it is slower as shifts and rotates are not fast instructions.
Bollocks!!!
And I knew about Endian order!! That proves the fact the one can only learn Assembly by practicing.... I was so focused on the algorithm that missed that...
Thanks Mineiro, Steve and Hutch!
Mineiro, my wife asked me why I am learning Assembly. I said I want to become a Painter, not a Photoshop editor (no offense intended). Well, that's how I feel about asm.
Hutch, any specific reason why intel suggested not using the high byte?
Quote from: hutch-- on February 15, 2017, 02:01:22 AMIn 32 bit you can access the two lowest bytes with AL and AH but for a long time Intel have advised against using the high byte and it 64 bit you cannot access it at all.
Well,
ah is not completely inaccessible (but you probably meant something else):
include \Masm32\MasmBasic\Res\JBasic.inc ; part of MasmBasic (http://masm32.com/board/index.php?topic=94.0)
Init ; OPT_64 1 ; put 0 for 32 bit, 1 for 64 bit assembly
PrintLine Chr$("This code was assembled with ", @AsmUsed$(1), " in ", jbit$, "-bit format")
mov ah, 123
; movzx rax, ah ; not possible
movzx eax, ah ; workaround; same result as movzx rax, ah but shorter
Print Str$("If ah is 123, then rax is now %lli\n\n", rax)
mov rax, 1234567890123456789
Inkey Str$("rax can be a really big number: %lli\n", rax)
EndOfCodeOutput:
This code was assembled with HJWasm32 in 64-bit format
If ah is 123, then rax is now 123
rax can be a really big number: 1234567890123456789
Quote from: LordAdef on February 15, 2017, 03:47:33 AM
Mineiro, my wife asked me why I am learning Assembly. I said I want to become a Painter, not a Photoshop editor (no offense intended). Well, that's how I feel about asm.
:eusa_clap:
I share the same opinion, persons that learn assembly are persons that don't simply accept things but like to understand the magic behind curtains.
You said about Photoshop, well, we can use photoshop as being a hexadecimal editor, but instead of see hexadecimal numbers we see colors, so, on theory we can program in assembly language by using Photoshop, it's hard I confess, but not impossible. Inverse can be done too, we can use an assembler to create a .gif,.bmp,..., it's hard but not impossible.
You're being a musician the same thing, but instead of see hexadecimal numbers on Audacity per example we see sinoidal waves.
> Hutch, any specific reason why intel suggested not using the high byte?
The reasoning from Intel at the time was it was a slower operation because of how the register was loaded and I think it goes back to the PIV era. You have had 2 major series of Intel hardware since, the Core2 series and the i3/5/7 series which may vary or are no longer bothered by it but for 64 bit operations, the high byte register is not available. JJ has shown how to access AH with a 32 bit operation but for a 64 bit operation, there is no opcode that will do it.
Quote from: hutch-- on February 15, 2017, 10:58:58 AMit was a slower operation because of how the register was loaded and I think it goes back to the PIV era.
Here is a little testbed:
align_64
TestA_s:
NameA equ mov al ; assign a descriptive name here
TestA proc
mov ebx, AlgoLoops-1 ; loop e.g. 100x
align 4
.Repeat
mov al, byte ptr somestring
mov cl, al
inc al
movzx eax, al
dec ebx
.Until Sign?
ret
TestA endp
TestA_endp:
align_64
TestB_s:
NameB equ mov ah ; assign a descriptive name here
TestB proc
mov ebx, AlgoLoops-1 ; loop e.g. 100x
align 4
.Repeat
mov ah, byte ptr somestring
mov ch, ah
inc ah
movzx eax, ah
dec ebx
.Until Sign?
ret
TestB endp
TestB_endp:
Results:
Intel(R) Core(TM) i5-2450M CPU @ 2.50GHz (SSE4)
127 cycles for 100 * mov al
53 cycles for 100 * mov ah
130 cycles for 100 * mov al
55 cycles for 100 * mov ah
126 cycles for 100 * mov al
52 cycles for 100 * mov ah
129 cycles for 100 * mov al
55 cycles for 100 * mov ah
127 cycles for 100 * mov al
55 cycles for 100 * mov ah
12 bytes for mov al
13 bytes for mov ah
The ah stuff is definitely one byte longer.
I tried to access the source code but it is unreadable RTF. What I would test is turning the two loops around because at the moment the code you posted is indicating that AH is faster than AL which does not make sense.
Posting examples in an unreadable format makes testing your algorithms unviable which is unfortunate because it renders them useless.
Quote from: hutch-- on February 15, 2017, 03:05:56 PM
I tried to access the source code but it is unreadable RTF.
RTF has been readable for almost 30 years now. Wordpad, for example, can read it; also MS Word, RichMasm (http://masm32.com/board/index.php?topic=5314.0), LibreOffice, ...
QuoteWhat I would test is turning the two loops around because at the moment the code you posted is indicating that AH is faster than AL which does not make sense.
Given that there is a REPEAT 5 ... ENDM around the code examples, there is obviously no need to exchange the order of the loops.
Anyway, for those who are not able to read RTF, attached a plain text version with loops "turned around". I agree, of course, that it "does not make sense" that ah is faster than al - maybe you can code something where it is the other round. Btw there is a switch in line 3 of the source:
useMB=0 - the second attachment contains the exe without any trace of MasmBasic (4096 bytes only), maybe the AH register behaves better without the influence of that library.
Intel(R) Core(TM) i5-2450M CPU @ 2.50GHz (SSE4)
57 cycles for 100 * mov ah
129 cycles for 100 * mov al
56 cycles for 100 * mov ah
122 cycles for 100 * mov al
56 cycles for 100 * mov ah
129 cycles for 100 * mov al
56 cycles for 100 * mov ah
129 cycles for 100 * mov al
56 cycles for 100 * mov ah
129 cycles for 100 * mov al
13 bytes for mov ah
12 bytes for mov al
:biggrin:
> RTF has been readable for almost 30 years now. Wordpad, for example, can read it; also MS Word, RichMasm, LibreOffice, ...
Trouble is that assemblers and compiler can't read it. Locking in a deviant code format to an exclusive editor makes the files unbuildable with anything else. Unless M$ have updated Word and Wordpad recently, they will not assemble MASM source code. Without a viable method to test the algos you post, there is no way of knowing what they do or how they are written.
With MASM it can be built with a batch file that does not require an editor at all and that can be tested by anyone who has a normal ascii text editor, Notepad and a whole host of others.
Quote from: hutch-- on February 16, 2017, 02:59:02 AMthere is no way of knowing what they do or how they are written.
You could open rich text (*.asc) files in Wordpad to see how they are written. If you don't trust my executables, you can press Ctrl A, Ctrl C, then switch to a poor text editor of your choice and build it there.
Never mind, from now on I'll try to add the poor text versions, too.
curious to know what's happening with al and ah in this code. it's an odd result indeed
Here is a simple benchmark testing the load time of AL and AH. Done on my 3.3 gig 6 core HASWELL.
This is the result.
688 load AL
1015 load AH
703 load AL
985 load AH
718 load AL
1000 load AH
735 load AL
984 load AH
703 load AL
1032 load AH
671 load AL
969 load AH
735 load AL
984 load AH
687 load AL
1000 load AH
Press any key to continue ...
This is the code.
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
include \masm32\include\masm32rt.inc
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
comment * -----------------------------------------------------
Build this template with
"CONSOLE ASSEMBLE AND LINK"
----------------------------------------------------- *
.data?
value dd ?
.data
item dd 0
.code
start:
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
call main
inkey
exit
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
main proc
push ebx
push esi
push edi
mov edi, 8
lpstart:
; -----------------------------------------------------------
mov esi, 1024*1024*1024 ; a power of 2, billion.
mov dl, 0
invoke GetTickCount
push eax
@@:
mov al, dl ; load AL
add dl, 1
cmp dl, 255
jne nxt
mov dl, 0
nxt:
sub esi, 1
jnz @B
invoke GetTickCount
pop ecx
sub eax, ecx
print str$(eax)," load AL",13,10
; -----------------------------------------------------------
mov esi, 1024*1024*1024 ; a power of 2 billion.
mov dl, 0
invoke GetTickCount
push eax
@@:
mov ah, dl ; load AH
add dl, 1
cmp dl, 255
jne nxt1
mov dl, 0
nxt1:
sub esi, 1
jnz @B
invoke GetTickCount
pop ecx
sub eax, ecx
print str$(eax)," load AH",13,10
; -----------------------------------------------------------
sub edi, 1
jnz lpstart
pop edi
pop esi
pop ebx
ret
main endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
end start
Interesting :t
I found my example a bit more relevant for practical purposes, but no problem, you found a case where mov ah is slow, congrats :icon14:
Btw how do the timings change with an align 4 before the two loops?
:biggrin:
> I found my example a bit more relevant for practical purpose
I took Intel's word on it and it seems like they know what they are talking about as they designed the hardware. May be different on AMD.
> Btw how do the timings change with an align 4 before the two loops?
I rarely ever align code these days as it often slows the code down. It was helpful at time with very old hardware, pre PIV but from the PIV onwards it often has the reverse effect.
Quote from: hutch-- on February 16, 2017, 11:24:39 AM
> Btw how do the timings change with an align 4 before the two loops?
I rarely ever align code these days as it often slows the code down. It was helpful at time with very old hardware, pre PIV but from the PIV onwards it often has the reverse effect.
With new hardware, such as my Core i5, an align 4 definitely speeds up the
mov ah part.
> With new hardware, such as my Core i5, an align 4 definitely speeds up the mov ah part
This is possibly the case as the Intel data indicated that a read or write to a high byte register involves an extra operation that is slower than a read/write to a low byte register and very vaguely it had to do with a masking operation to get the high byte.
I will make the point though that writing legacy code in either 32 or 64 bit is a mistake, it simply cannot be done as a 64 bit operation and while your example in 32 bit in 64 bit code did work, you will get stung in performance terms by doing things like that. At least in 64 bit code you have more BYTE registers which removes the need to use antique code.
deleted
Quote from: nidud on February 16, 2017, 10:50:13 PM
Here's a simple 64-bit test-bed without any alignment problems.
Can't be :(
Intel(R) Core(TM) i5-2450M CPU @ 2.50GHz (AVX)
----------------------------------------------
-- test(1)
553579 cycles, rep(3000), code(801) 0.asm: load AL
428491 cycles, rep(3000), code(801) 1.asm: load AH
-- test(2)
539858 cycles, rep(3000), code(801) 0.asm: load AL
429470 cycles, rep(3000), code(801) 1.asm: load AH
-- test(3)
532109 cycles, rep(3000), code(801) 0.asm: load AL
433764 cycles, rep(3000), code(801) 1.asm: load AH
total [1 .. 3], 1++
1291725 cycles 1.asm: load AH
1625546 cycles 0.asm: load AL
Here is what it looks like in 64 bit MASM, the load to AH is even slower.
Run on my 3.3gig Haswell.
703 load AL
1203 load AH
656 load AL
1172 load AH
672 load AL
1156 load AH
672 load AL
1203 load AH
719 load AL
1156 load AH
672 load AL
1156 load AH
672 load AL
1156 load AH
672 load AL
1156 load AH
That's all folks .....
RE: The testing method. The virtues of real time testing versus interpreted testing.
File attached.
mov rsi, 1024*1024*1024 ; a power of 2, billion.
mov dl, 0
invoke GetTickCount
push rax
@@: ; -------
mov ah, dl ; load AH <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
add dl, 1 ; -------
cmp dl, 255
jne nxt1
mov dl, 0
nxt1:
sub rsi, 1
So at least we now have an official confirmation that AH can be used in 64-bit code. But the mystery remains:
1. why is Nidud's test so much faster for AH? repeat 200
mov dl,ah
mov ah,bl
endm
2. why is Hutch' test so much slower for AH? @@: ; -------
mov ah, dl ; load AH
add dl, 1 ; -------
cmp dl, 255
jne nxt1
mov dl, 0
nxt1:
sub rsi, 1
jnz @B
Anybody here from Intel who could enlighten us?
P.S.: What does the 64-bit Windows ABI say about preserving regs?
mov dl, 0
invoke GetTickCount
> 2. why is Hutch' test so much slower for AH?
Testing in real time !
Here is a variation on the first test, remove the PUSH POP from both examples and the load AH code got faster. Replace it with r15. The load AH is still a lot slower
703 load AL
1031 load AH
703 load AL
985 load AH
687 load AL
1063 load AH
734 load AL
1016 load AH
687 load AL
1016 load AH
687 load AL
1016 load AH
703 load AL
1016 load AH
734 load AL
1016 load AH
That's all folks .....
The code.
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
include \masm32\include64\masm64rt.inc
.code
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
entry_point proc
LOCAL .rsi :QWORD
LOCAL .rdi :QWORD
LOCAL .r15 :QWORD
mov .rsi, rsi
mov .rdi, rdi
mov .r15, r15
mov rdi, 8 ; the loop counter
lpstart:
; -----------------------------------------------------------
mov rsi, 1024*1024*1024 ; a power of 2, billion.
mov dl, 0
invoke GetTickCount
mov r15, rax
@@: ; -------
mov al, dl ; load AL
add dl, 1 ; -------
cmp dl, 255
jne nxt
mov dl, 0
nxt:
sub rsi, 1
jnz @B
invoke GetTickCount
mov rcx, r15
sub rax, rcx
conout str$(rax)," load AL",lf
; -----------------------------------------------------------
mov rsi, 1024*1024*1024 ; a power of 2, billion.
mov dl, 0
invoke GetTickCount
mov r15, rax
@@: ; -------
mov ah, dl ; load AH
add dl, 1 ; -------
cmp dl, 255
jne nxt1
mov dl, 0
nxt1:
sub rsi, 1
jnz @B
invoke GetTickCount
mov rcx, r15
sub rax, rcx
conout str$(rax)," load AH",lf
; -----------------------------------------------------------
sub rdi, 1
jnz lpstart
conout lf
waitkey "That's all folks ....."
mov rsi, .rsi
mov rdi, .rdi
mov r15, .r15
invoke ExitProcess,0
ret
entry_point endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
end
deleted
Thanks for that, I don't have an AMD box to test with.
Another AMD E1
3328 load AL
3297 load AH
3281 load AL
3266 load AH
3297 load AL
3297 load AH
3265 load AL
3282 load AH
3281 load AL
3281 load AH
3281 load AL
3297 load AH
3282 load AL
3265 load AH
3297 load AL
3281 load AH
That's all folks .....
Hi,
FWIW.
; - - -
{P-III}
; - - -
pre-P4 (SSE1)
104 cycles for 100 * mov ah
105 cycles for 100 * mov al
104 cycles for 100 * mov ah
105 cycles for 100 * mov al
103 cycles for 100 * mov ah
105 cycles for 100 * mov al
105 cycles for 100 * mov ah
108 cycles for 100 * mov al
104 cycles for 100 * mov ah
104 cycles for 100 * mov al
13 bytes for mov ah
12 bytes for mov al
--- ok ---
; - - -
P-MMX
; - - -
pre-P4
489 cycles for 100 * mov ah
505 cycles for 100 * mov al
489 cycles for 100 * mov ah
513 cycles for 100 * mov al
529 cycles for 100 * mov ah
592 cycles for 100 * mov al
496 cycles for 100 * mov ah
517 cycles for 100 * mov al
499 cycles for 100 * mov ah
518 cycles for 100 * mov al
13 bytes for mov ah
12 bytes for mov al
--- ok ---
; = = =
Intel(R) Core(TM) i3-4005U CPU @ 1.70GHz (SSE4)
74 cycles for 100 * mov ah
163 cycles for 100 * mov al
74 cycles for 100 * mov ah
162 cycles for 100 * mov al
74 cycles for 100 * mov ah
162 cycles for 100 * mov al
74 cycles for 100 * mov ah
162 cycles for 100 * mov al
74 cycles for 100 * mov ah
162 cycles for 100 * mov al
13 bytes for mov ah
12 bytes for mov al
--- ok ---
; - - -
Intel(R) Core(TM) i3-4005U CPU @ 1.70GHz (AVX2)
----------------------------------------------
-- test(1)
613736 cycles, rep(3000), code(801) 0.asm: load AL
542611 cycles, rep(3000), code(801) 1.asm: load AH
-- test(2)
620431 cycles, rep(3000), code(801) 0.asm: load AL
535470 cycles, rep(3000), code(801) 1.asm: load AH
-- test(3)
628891 cycles, rep(3000), code(801) 0.asm: load AL
532790 cycles, rep(3000), code(801) 1.asm: load AH
total [1 .. 3], 1++
1610871 cycles 1.asm: load AH
1863058 cycles 0.asm: load AL
hit any key to continue...
HTH,
Steve N.
align 8
@@:
mov ah, byte ptr somestring
mov ch, ah
inc ah
movzx eax, ah
dec ebx
jns @B
align 8
@@:
mov al, byte ptr somestring
mov cl, al
inc al
movzx eax, al
dec ebx
jns @B
Results for a Core i5, one Billion iterations:
This code was assembled with ML in 64-bit format
671 ms for AH
1014 ms for AL
655 ms for AH
983 ms for AL
656 ms for AH
982 ms for AL
640 ms for AH
983 ms for AL
671 ms for AH
982 ms for AL
No speed difference between 64-bit and 32-bit code. Sources (rich text, poor text) and executables built with ML, ML64, AsmC and HJWasm32 attached.
P.S.: What exactly is "real time", and how is it different to what?
Quote from: hutch-- on February 17, 2017, 01:31:54 AMTesting in real time !
I wouldn't have imagined such different results...
I'll run the test here and post my results too. Win7 64b on i7
:biggrin:
> P.S.: What exactly is "real time", and how is it different to what?
The stuff you wake up to in the morning, stop to each your lunch by, go to the pub after work by and what you set the alarm clock for. I have warned you for a long time that your timing technique is unsound, there are too many interpretive layers and too many variables that can produce misleading results. The other factor is that cycle counts went out the door with a 486dx.
The reason why I still use a very crude low level timing technique run long enough to avoid task switching is because it assumes only 1 thing, how long it takes. Using misleading timing techniques may justify using obsolete instructions but you won't get fast code for doing it.
Quote from: hutch-- on February 17, 2017, 11:52:37 AMI have warned you for a long time that your timing technique is unsound
Thanks for the warning. I am so sorry that you consider my coding garbage (http://masm32.com/board/index.php?topic=5962.msg63519#msg63519), Hutch, but please explain to me how I could improve the loops below to make them "sound real timing"?
From attachment to Reply #87, MovAh_JJ_DualAssembly.asm (plain text, opens even in qEditor.exe):
MainLoop:
mov ebx, AlgoLoops-1 ; OxPT_Assembler ML ; delete the x to pick another assembler
push rax ; keep the stack aligned
push rv(GetTickCount)
align 8
@@:
mov ah, byte ptr somestring
mov ch, ah
inc ah
movzx eax, ah
dec ebx
jns @B
jinvoke GetTickCount
pop rdx
pop rcx
sub rax, rdx
Print Str$("%i ms for AH\n", rax)
mov ebx, AlgoLoops-1
push rax ; keep the stack aligned
push rv(GetTickCount)
align 8
@@:
mov al, byte ptr somestring
mov cl, al
inc al
movzx eax, al
dec ebx
jns @B
jinvoke GetTickCount
pop rdx
pop rcx
sub rax, rdx
Print Str$("%i ms for AL\n\n", rax)
dec esi
jns MainLoop
There is not enough in your snippet to make sense of it. Missing bits and limited commenting.
Here is an even less interpreted benchmark, 2 x 3 instruction loops ran 8 times sequentially and displayed on the screen. I have done everything I could think of to try and stabilise the timings of the high byte to high byte register copies, aligned each label by 16, set a higher priority class, untangled the mixed 32/64 bit instructions but the low byte register copies are clearly faster on this Haswell I am using. Still, I don't understand why you want to use legacy code like this when you have a lot more registers to work with.
984 ms high byte load
672 ms low byte load
1031 ms high byte load
687 ms low byte load
1016 ms high byte load
672 ms low byte load
1016 ms high byte load
657 ms low byte load
1000 ms high byte load
625 ms low byte load
984 ms high byte load
656 ms low byte load
1000 ms high byte load
640 ms low byte load
1000 ms high byte load
672 ms low byte load
Press any key to continue...
This is the test piece.
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
include \masm32\include64\masm64rt.inc
.code
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
entry_point proc
LOCAL .rsi :QWORD
LOCAL .rdi :QWORD
LOCAL .rbx :QWORD
LOCAL .r15 :QWORD
mov .r15, r15
mov .rbx, rbx
mov .rdi, rdi
invoke SetPriorityClass,rv(GetCurrentProcess),HIGH_PRIORITY_CLASS
chnm equ <255> ; single number to write
lcnt equ <1024*1024*1024*2> ; loop iteration count
algn equ <16> ; alignment
dlay equ <100> ; delay for SleepEx
mov rdi, 8
startlabel:
; ----------------------------
invoke SleepEx,dlay,0
mov rbx, lcnt
invoke GetTickCount
mov r15, rax
xor rax, rax
xor rdx, rdx
mov dh, chnm
align algn
@@:
mov ah, dh ; load HIGH BYTE to HIGH BYTE
sub rbx, 1
jns @B
invoke GetTickCount
sub rax, r15
conout str$(rax)," ms high byte load",lf
; ----------------------------
invoke SleepEx,dlay,0
mov rbx, lcnt
invoke GetTickCount
mov r15, rax
xor rax, rax
xor rdx, rdx
mov dl, chnm
align algn
@@:
mov al, dl ; load LOW BYTE to LOW BYTE
sub rbx, 1
jns @B
invoke GetTickCount
sub rax, r15
conout str$(rax)," ms low byte load",lf
; ----------------------------
sub rdi, 1
jnz startlabel
invoke SetPriorityClass,rv(GetCurrentProcess),NORMAL_PRIORITY_CLASS
waitkey
mov r15, .r15
mov rbx, .rbx
mov rdi, .rdi
invoke ExitProcess,0
ret
entry_point endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
end
Hi there, I´m still doing my things and I believe I´m making some progress....
I´m attaching below 2 little progs for you.
The first one is a new algo I wrote for my scrolling map. It´s smoother, and can be controlled by key for better tests.
The other is an idea I coded for the "splash screen texts" in between game levels. Just an idea for a non expensive solution.
UPDATE 1: New algo for the scrolling map.
I´m still soly tasting the waters. But I´m introducing some structures and so on.
Size is about 4k. Memory steady at 3.616
1. Ok, I tried many things and read a lot from you here in the forum. Hard coding the scroll map seems the best way to go I guess. I tried ScrollWindowsEx but I loose control of things (although it´s a lot smoother).
2. I definitely need a better mouse solution, this one doesn´t do and I know why. But it will do for now.
You can use the arrows:
Left/right: move our guy sideways
UP/Down: accelerates/decelerates the map
3. I got rid of all RGB macros since I don´t need them at runtime. I rather got prefixed hex values in a struct. But I think they would be better as const. (is it possible to make a const. struct.?? It bothers me to have all those variables floating around)
4. I´m slowly implementing a gameState control for the game design.
Any feedback will be more than welcome!
Alex
UPDATE 2: Splash screen prototype
I wrote this as an idea for inter levels splash screens. It emulates someone typewriting, then it fades the text out and turn it into black. I think it´s elegant and minimalistic for such a simple game.
1.
Warning: I´m using a 100% free typewriter font. You need to install it to run the prog. I could´ve used AddFontResourceEx/RemoveFontResourceEx but that would temporarily install the font, and I´m not sure if this is consider "ok". So I didn´t, please let me know how to go about this? (font attached in a folder plus copyrights clearance)
2. This is interesting:
qEditor complains about this line:
Quoteinvoke CreateFont, 17,0,0,0,400,0,0,0, ANSI_CHARSET, 0, 0,0,0, ADDR chr$("Sears Tower") ;NOT good in qEditor
RichMasm doesn´t!
However... qEditor is fine with these ones in my other prog:
Quoteinvoke CreateFont,12,0,0,0,400,0,0,0,OEM_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,\
DEFAULT_QUALITY,DEFAULT_PITCH or FF_SCRIPT, chr$("Courier New")
What´s happening with this?
3. Can we play mp3 instead of a .wav file? It´s tremendously big for a simple typewriter sound (37kb), unless I really bring the sample rate down. What´s the suggestion?
Cheers
Alex
Alex,
ADDR chr$("Sears Tower")
This will not work in MASM32, try it without the ADDR as this looks like its a pointer to the pointer that "chr$" returns.
Now I tried your last post, left to right works but a bit sluggish, the forward could be slowed up but I could not get it to run in reverse.
Quote from: hutch-- on February 20, 2017, 05:40:14 PM
Alex,
ADDR chr$("Sears Tower")
This will not work in MASM32, try it without the ADDR as this looks like its a pointer to the pointer that "chr$" returns.
Yes! it´s working as you said, cheers.
QuoteNow I tried your last post, left to right works but a bit sluggish,
Possibly 2 things Hutch:
a. I´m incrementing its y coord by 8
b. I´m intentionally not invalidateRect there. I get some memory leak when I do it, I still need to work on this
Could it be this what you meant or something else?
Quote.ELSEIF uMsg == WM_KEYDOWN
.IF wParam == VK_LEFT
add man.x, -8
.ELSEIF wParam == VK_RIGHT
add man.x, 8
.ELSEIF wParam == VK_UP
Quotethe forward could be slowed up but I could not get it to run in reverse.
I´m not allowing it to reverse. When you reach speed 8 there´s a jump in speed. Same when speed= 2, and 0. It´s me trying to change different variables in there
I will work on the key code Hutch. But there is this problem with WM_KEYDOWN. There is this auto repeat feature I don´t know how to change or deal with. So KEYDOWN is really unusable as of now:
msdn:
QuoteThe repeat count for the current message. The value is the number of times the keystroke is autorepeated as a result of the user holding down the key. If the keystroke is held long enough, multiple messages are sent. However, the repeat count is not cumulative.
QuoteBecause of the autorepeat feature, more than one WM_KEYDOWN message may be posted before a WM_KEYUP message is posted. The previous key state (bit 30) can be used to determine whether the WM_KEYDOWN message indicates the first down transition or a repeated down transition.
Quote from: LordAdef on February 20, 2017, 05:33:11 PM
qEditor complains about this line:
Quoteinvoke CreateFont, 17,0,0,0,400,0,0,0, ANSI_CHARSET, 0, 0,0,0, ADDR chr$("Sears Tower") ;NOT good in qEditor
RichMasm doesn´t!
Alex,
Strictly speaking this is not RichMasm's merit, but rather due to the fact that RM uses HJWasm32 by default. Try to add this under your code:
OPT_Assembler ML
and voilà: error A2033:invalid INVOKE argument : 14
One could argue that all assemblers should throw an error here. Of course, your intention is clear: "addr chr$()". But it's incorrect syntax from a MASM point of view. @HJWasm+AsmC teams: what about a little warning?
Re RGB macros, they can be very compact, i.e. they do not add much code. Have a look at this snippet through the eyes of Olly, it uses RGB (original Masm32 macro) and RgbCol() (http://www.webalice.it/jj2006/MasmBasicQuickReference.htm#Mb1331):
include \masm32\MasmBasic\MasmBasic.inc
Init
int 3
RGB 12h, 34h, 56h ; Masm32 macro
print hex$(eax), 13, 10
PrintLine Hex$(RgbCol(12h, 34h, 56h)) ; MasmBasic equivalent
mov eax, 12h
mov ecx, 34h
mov edx, 56h
PrintLine Hex$(RgbCol(eax, ecx, edx))
mov eax, 12h
mov ecx, 34h
mov edx, 56h
if 0 ; not possible:
RGB eax, ecx, edx
else ; but this works:
mov eax, RgbCol(eax, ecx, edx)
endif
print hex$(eax), 13, 10
inkey "ok?"
EndOfCode
Even this works, btw:
PrintLine "Gradual colour change:"
For_ ecx=0 To 255 Step 11h
PrintLine Hex$(RgbCol(22h, ecx, 44h))
NextOutput:
Gradual colour change:
00440022
00441122
00442222
00443322
00444422
00445522
00446622
00447722
00448822
00449922
0044AA22
0044BB22
0044CC22
0044DD22
0044EE22
0044FF22
Quote from: LordAdef on February 20, 2017, 06:04:34 PMThere is this auto repeat feature I don´t know how to change or deal with. So KEYDOWN is really unusable as of now:
What exactly is the problem there?
Hi JJ,
I was using the RGB macro. The thing is, there´s no need to waste processor time when I know the colours I need. The code and debugger gets cleaner. What I will chance is forget the colour structure and make them const.
Re Keyboard, I get back to you later today. I need either getKeyboardState or ASync.... (I know getKeyboard.. is slower, so I might try the other one). This is how I implemented my game in C. Although I used the SDL library, the principle worked.
But here is a quicky one:
I decided to clean up my asm file. I created an inc called "stuff.inc" with protos, structs. I also put the Windows shite as a macro so I don´t need to stare at it all the time:
Quote
;------------------- PROTOTYPES ---------------------------------------------------------------------------
WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD
pLoad PROTO :DWORD
pIni PROTO
pIniFonts PROTO :DWORD
pSetGameState PROTO :DWORD
;------------------------- STRUCTS ----------------------------------------------------------------------
RGB macro red,green,blue
xor eax,eax
mov ah,blue
shl eax,8
mov ah,green
mov al,red
endm
;---------------------
;--- STRUCTURES ------
;---------------------
Game STRUCT
lives dd ?
level dd ?
state dd ?
speed dd ?
dispRect RECT <>
Game ENDS
Map STRUCT
scroll dd ?
linevstart dd ?
line dd ?
yspace dd ?
Map ENDS
Player STRUCT
speed dd ?
x dd ?
y dd ?
angle dd ?
tx dd ?
ty dd ?
Player ENDS
Enemy STRUCT
speed dd ?
Enemy ENDS
Bullet STRUCT
speed dd ?
Bullet ENDS
Colours STRUCT
white dd ?
yellow dd ?
bk dd ?
display dd ?
Colours ENDS
;------------------- MACROS -----------------------------------------------------------------------------------
MacroDisplay macro
; ------------------ TEMPORARY HERE FOR TESTS ----------------------
; Debug display:
invoke TextOut,hdc, 0, 600, chr$("Speed:"), 6
invoke TextOut,hdc, 30, 600, str$(gm.speed), 3
invoke TextOut,hdc, 0, 620, chr$("line:"), 6
invoke TextOut,hdc, 30, 620, str$(map.line), 4
; --------- print DISPLAY ------------------------------------
invoke SelectObject, hdc, Font4 ; display labels
invoke SetTextColor,hdc, colours.display
invoke SetBkMode, hdc, TRANSPARENT
invoke TextOut,hdc,10,60, chr$("Level"), 5 ;ADDR Label1, 5
invoke TextOut,hdc,10,300, chr$("Lives"), 5 ;ADDR Label1, 5
invoke SelectObject, hdc, Font3
invoke SetTextColor,hdc, colours.display
invoke SetBkMode, hdc, TRANSPARENT ; display values
invoke TextOut,hdc,20,90, str$(gm.level), 1 ;ADDR Label1, 5
invoke TextOut,hdc,20,330, str$(gm.lives), 1 ;ADDR Label1, 5
; -----------------------------------------------------------
endm
macroWinMain macro
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInst
pop wc.hInstance
mov wc.hbrBackground,COLOR_WINDOW+2
mov wc.lpszMenuName,NULL
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor, eax
invoke RegisterClassEx, addr wc
invoke CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,WS_OVERLAPPEDWINDOW,\
500,10, 900,850,NULL,NULL,hInst,NULL
mov hwnd,eax
invoke ShowWindow, hwnd,SW_SHOWNORMAL
invoke UpdateWindow, hwnd
endm
The question is.....Before this move my prog was running steady at
3.610 kb.
After this move I´m getting a
steady 1.496 kb.... Where is the remaing kbs?? I´m sure they are somewhere..everything is working as it should
Alex,
I would be inclined to only use the Windows keyboard messages to start and finish the key operations but to get an adjustable repeat rate, I would set up a thread with a timer where you set the repeat rate yourself and trigger the screen movement with your own delay rate.
Quote from: hutch-- on February 21, 2017, 05:48:28 AM
Alex,
I would be inclined to only use the Windows keyboard messages to start and finish the key operations but to get an adjustable repeat rate, I would set up a thread with a timer where you set the repeat rate yourself and trigger the screen movement with your own delay rate.
Well, I know I can set more than one timer, but I´m not sure how I could implement that in my actual state of personal development :)
The main issue is windows have this repeat count for KeyDown and apparently it shows it at bit 30. I have no bloody clue how to change that ::)
Hutch, how about this size change in my device manager after I´ve created the inc file. Is this normal?
Hutch. I BLOODY GOT IT. Keys working like a charm now
QuotepKeyEvents proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
invoke GetAsyncKeyState, VK_RIGHT
AND ax, 8000h
cmp ax, 32768
jz Right
invoke GetAsyncKeyState, VK_LEFT
AND ax, 8000h
cmp ax, 32768
jz Left
invoke GetAsyncKeyState, VK_UP
AND ax, 8000h
cmp ax, 32768
jz Up
invoke GetAsyncKeyState, VK_DOWN
AND ax, 8000h
cmp ax, 32768
jz Down
jmp @F
Right:
add man.x, 2 ;8
jmp @F
Left:
sub man.x, 2
jmp @F
Up:
macroSpeedUP
jmp @F
Down:
macroSpeedDown
@@:
ret
pKeyEvents endp
:biggrin:
> Hutch. I BLOODY GOT IT. Keys working like a charm now :t
Quote from: LordAdef on February 21, 2017, 06:32:54 AMinvoke GetAsyncKeyState, VK_RIGHT
AND ax, 8000h
cmp ax, 32768
jz Right
invoke GetAsyncKeyState, VK_RIGHT
test ah, ah
js Right
same result ;)
Quoteinvoke GetAsyncKeyState, VK_RIGHT
AND ax, 8000h
cmp ax, 32768
jz Right
And I thought I was being very clever here, since I pulled this off by myself! Cheers JJ, I updated the code with your suggestion.
I attached the prog updated with the latest suggestions. I also now have a bitmap airplane, check it out!
I took this bitmap code from Iczelion. It´s a first timer here too among a thousand this week.
Just checking: Do I need to keep all of these inside my PAINT loop?
Quote;------- AIRPLANE -----------------
invoke CreateCompatibleDC,hdc
mov hMemDC,eax
invoke SelectObject,hMemDC,hBitmap
invoke GetClientRect,hWnd,addr rect
invoke BitBlt,hdc, man.x, man.y, rect.right, rect.bottom, hMemDC, 0, 0, SRCPAINT ;SRCCOPY
invoke DeleteDC,hMemDC
;--------------------------------------------------------------------------------------------------------------
You can probably get away with putting the open and close GDI resource code in your startup/exit code but keep an eye on the device context count and also check your memory usage after running the app for a while.
It looks nice :t
thanks Caballero
This one works well, just downloaded and tested it and the left right keys navigate the plane with no lag at all. :t
Quote from: hutch-- on February 22, 2017, 12:32:44 PM
This one works well, just downloaded and tested it and the left right keys navigate the plane with no lag at all. :t
Nice Hutch!
Well, today I complete a full month as part of the Masm32 community!
I guess you wont get rid of me any soon :eusa_naughty:
I made some small little cleaning, and put some animation for my airplane. Attached the exe, just for fun.
Cheers, Alex
Very cute, compliments :t
Hi guys,
I created another actor for the game, a Bomber. While testing the little guy, I could not make it look right. Its body is transparent although the colour background is fine. Just run the exe and see what I mean (What matters is when inside the map, I left it bleed on the left side on purpose) .
The temp code is this one below (it´s just for test):
Quote;-------------- TESTING ONLY! --------------
mov eax, map.line
add eax, edi
Switch eax
Case 470 ;this is line
mov bomber.y, ebx
Endsw
invoke SetTextColor,hdc, colBOMBER
invoke BitBlt, hdc, bomber.x, bomber.y, 36, 35, hMemDCbomber, 0, bomber.frmy, SRCPAINT ;
The file for the Bomber is "Bomber.bmp", 1 bit.
Any hint on how to work this out?
Cheers!
ps: For those who don´t remember River Raid for Atari, I found this link:
https://www.youtube.com/watch?v=kNXQYH-xTK8 (https://www.youtube.com/watch?v=kNXQYH-xTK8)
What I´m doing is a loose recreation of River Raid, more of a inspiration in fact. As you can see, there are these Bombers in the original game, but they don´t follow the map and run horizontally. I changed that.
ps2: Some small changes: Windows is not resizable anymore, colours are constants
That's nice. I guess that if you fly outside the river you will lose.
Exactly Caballero!
I still need to write the collision detection algorithm. There is where the fun is!
Update on the transparency & bombers:
I managed to make it to work, but it´s a very expensive solution and it´s bloating my exe file... I really need someone to suggest me a cheaper solution, please.
I´m using two bmp: 1 bit one and the other is 4 bits (it doesn´t work with 2 1bits)
I´m using 2 bitblt lines (attached as separate files in the zip):
Quoteinvoke SetTextColor,hdc, colBOMBER
invoke BitBlt, hdc, bomber.x, bomber.y, 36, 35, hMaskDC, 0, bomber.frmy, SRCAND
invoke BitBlt, hdc, bomber.x, bomber.y, 36, 35, hMemDCbomber, 0, bomber.frmy, SRCPAINT
So, a veeery expensive solution for a small detail.
As a bonus, due to the
FANTASTIC Switch/case in MASM I put 5 little guys flying for you.
Quote;-------------- TESTING ONLY! --------------
mov eax, map.line
add eax, edi
Switch eax
Case 450, 440, 430, 400, 390 ;this is line. 5 planes at given lines
mov bomber.y, ebx
Endsw
Any help is welcomed
Cheers Alex
ps: asm and Richmasm files included.
Quote from: LordAdef on March 01, 2017, 12:56:21 PM
I´m using 2 bitblt lines (attached as separate files in the zip):
...
So, a veeery expensive solution for a small detail.
Hi Alex,
Test this:
;xxxxxxxxxxxxxxxxxxxxxxxxx
; ASCii Raid. game foundation
;xxxxxxxxxxxxxxxxxxxxxxxxx
include \masm32\MasmBasic\MasmBasic.inc
; include \masm32\include\masm32rt.inc
include stuff.inc ;protos, structs, macros
...
NanoTimer()
invoke BitBlt, hdc, bomber.x, bomber.y, 36, 35, hMaskDC, 0, bomber.frmy, SRCAND
invoke BitBlt, hdc, bomber.x, bomber.y, 36, 35, hMemDCbomber, 0, bomber.frmy, SRCPAINT
Print Str$("%i us ", NanoTimer(us))
The animation will not work properly, but it's just for showing how expensive your solution really is 8)
QuoteThe animation will not work properly, but it's just for showing how expensive your solution really is 8)
Hi JJ,
This is what I´ve got from 2 scenarios:
1st line:
Quoteinvoke BitBlt, hdc, bomber.x, bomber.y, 36, 35, hBomberDC, 0, bomber.frmy, SRCPAINT
2nd line:
Quoteinvoke BitBlt, hdc, bomber.x, bomber.y, 36, 35, hMaskDC, 0, bomber.frmy, SRCAND
invoke BitBlt, hdc, bomber.x, bomber.y, 36, 35, hBomberDC, 0, bomber.frmy, SRCPAINT
Quote5 us 9 us 24 us 10 us 46 us 24 us 21 us 21 us 18 us 38 us 36 us 21 us 23 us 20 us 19 us 19 us 28 us 35 us 23 us 22 us 22 us 22 us 20 us 15 us 27 us 23 us 21 us Average: 21
23 us 9 us 82 us 7 us 30 us 27 us 26 us 33 us 42 us 29 us 25 us 24 us 21 us 33 us 29 us 25 us 54 us 27 us 23 us 36 us 27 us 24 us 24 us 25 us 24 us 25 us 24 us Average: 28
Interesting test. And it´s good because I was lacking a way to time my code. I will now be using your macros to time it further.
Apart from any performance issue, I am actually suffering with the extra 2.57kb I´m having to add to my payload (on top of the 1bit 902 bytes for the same actor).
Do you think this is a nice solution then?
Disclaimer:
It´s all you guys´s fault, I´m turning into this miserable programmer crying for every byte added, and every tick lost :dazzled:
I blame you and Hutch!!! :badgrin:
:biggrin:
> I blame you and Hutch!!!
If in doubt, choose speed over size.
If not in doubt, choose speed over size.
If all else fails, choose speed over size.
Don't care what others do, choose speed over size.
And if none of that works, make it go fast !!!!
Quote from: hutch-- on March 02, 2017, 07:22:12 PM
:biggrin:
If in doubt, choose speed over size.
If not in doubt, choose speed over size.
If all else fails, choose speed over size.
Don't care what others do, choose speed over size.
And if none of that works, make it go fast !!!!
noted Hutch!
That's why I'm still trying to figure out a way to optimize this bit, but can't find a solution. The small little losses will be summing into a performance drawback. That's why I'm going slowly, and not pilling up code.
Quote from: LordAdef on March 02, 2017, 07:15:25 PM
Average: 28
Interesting test.
Indeed: 28
microseconds. If you consider that a smooth video display requires around 20 frames per second, then a single frame needs 50 milliseconds. So you are a factor 2000 faster than required. There is
no performance problem, your solution with the two bitmaps is the right one :t
Hello my friends!
I was working on the map´s RLE. I managed to compress it from 90kb to 2.485 bytes.
The code is not optimized and I was really lazy in many places, but I really wanted it to do its job asap.
I know I could´ve used some macros (like "cmpmem" and many others) that would´ve made my life easier. But I chose to do it all by myself and learn from it.
The byte data looks like this:
Quote67 -15 0 0 0 0 67 -16 0 66 -17 65 -17 64 -18 63 -19 61 -21 .....
That´s the output:
Quote== COMPRESSING FILE ==
1. Adding dwords from orig. file
2. filtering chars
3. parsing
4. checking for equal lines and building Flag array
Flags array:
01111010000000000010000000000000000000000000000001001000001111100011111111110010
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000101110000000000000000000000000000000000000000000000000000000000000000000
00001000000000000000000000000000000000000000000010000000000110000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000001001
00100000100000001001100010011000110011111111111001000111111000010111100010110010
5. Building final array
6. done.
=============== REPORT ================
file format:[dd Orig.Size][dd lineCount][dd LineLenght][data:BYTE @sp@-sp ?]
Original size= 89997
New size= 2485
Number of lines= 558
Lengh of line= 159
Equal Lines found= 71
Done...
that list of 0/1s is my lazy way to optimize repeated lines.
Again, it needs a lot of cleaning up, but it works.
RichMasm and Asm files attached.
A curiosity: qEditor complained about "print str$(al)". I used print str$(eax) instead.
Now I have to make it read it back.
Last but not least: I ran some speed tests and what I got suggests .If macro is slower than the Switch/case macro. Is there a common sense on this?
.IF vs Case vs Case_:
Quote.IF 564 241 237 349 273 277 410 193 277 375
Case 188 245 183 205 162 163 183 161 155 165
Quote from: LordAdef on March 19, 2017, 07:05:02 PMA curiosity: qEditor complained about "print str$(al)". I used print str$(eax) instead.
That is not qEditor's fault. The Masm32 str$() is just less flexible than Str$() (http://www.webalice.it/jj2006/MasmBasicQuickReference.htm#Mb1186).
Quote.If macro is slower than the Switch/case macro. Is there a common sense on this?
There is no consensus but instead, with forum search (http://masm32.com/board/index.php?action=search;advanced;search=) for
switch timings you can find long threads like this one (http://masm32.com/board/index.php?topic=5539.msg59193#msg59193) :P
Nice work btw :t
If you have many identical lines, sorting them before encoding might be interesting.
Thanks JJ,
QuoteThat is not qEditor's fault. The Masm32 str$() is just less flexible than Str$().
I´m sure it isn´t. But it must be something between ML.exe and JWasm. I used the masm32rt to built it.
QuoteIf you have many identical lines, sorting them before encoding might be interesting.
I thought of that, and it would be a lot easier. This map has 71 repeated lines, within 558 lines with 159 chars/line. My reasoning was that doing it afterwards (although more complicated in the logic) would be
shorter faster.
Alex,
The "str$()" macro in MASM32 is specifically for DWORD values, basic emulation and assembler are not the same thing. To use the str$() macro on smaller values you use MOVZX to make it the right size.
Hello sir LordAdef;
we have different instructions to compare data, default is 'cmp', but if you are comparing if something is zero, you can use logical 'or', or 'test', or by some assumptions use dec or sub, ... . These instructions can do same thing but how much efficient is to be measure.
I consider code below an ugly code because use a lot of data and little code, one to one byte relation.
;========== FILTER UNWANTED CHARS ====================
;I don't have assembled, can appear sintax errors
printf (" 2. filtering chars\n")
mov ecx, tLen ;.if tLen == 0, abort
or ecx,ecx ;test ecx,ecx?
jz done
push esi
filter:
movzx eax,[esi] ;load a byte data from source
movzx eax,[eax + mytable] ;compute data
or eax,eax ;.if data == 0 ignore
jz ignore_this_data
mov [esi],al ;insert transformed data
ignore_this_data:
inc esi ;next data
dec ecx ;tLen-1
jnz filter
pop esi
done:
.data
align 16
mytable label dword ;byte to byte relation
db 00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h
db 00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h
db 00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h
db 00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h," ",00h,00h
db 00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h
db 00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h
db "@",00h,"@",00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h
db 00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h
db 00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h
db 00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h
db 00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h
db 00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h
db 00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h
db 00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h
db 00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h
db 00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h
.code
I don't have tried to optimize this code, maybe can use cmovxx instructions, ... , I only posted this code to show a way to try to avoid many comparisions.
If you include others signs like "{","}","(",")", so you only need change the byte relation on data table instead of create more code with comparisions.
This tabled code supposed reach a constant time execution, while when inserting compares the execution time changes at each insertion of new signs. The tabled way is usefull too if you like to do your program portable to other chips like microcontrollers. Imaginate a table like hexstring_to_hex, on pc we can just 'mov' to convert and on others chips too, but if there so much code done to PC, will get harder to port that code to others processors/microcontrolers. Well, I'm getting offtopic, "the good, the bad and the ugly" theme song.
edited after: removed an unecessary push instruction.
Hi Mineiro, my dear fellow country man,
Nice to see you here!
Quoteprintf (" 2. filtering chars\n")
xor edi, edi
filter:
movzx ebx, BYTE Ptr [esi + edi]
Switch ebx
Case '=' ; = is nothing, for tests only
mov BYTE Ptr [esi + edi], " "
Case 60, 62 ; < > are bombers signs
mov BYTE Ptr [esi + edi], '@'
Endsw
add edi, 1
cmp edi, tLen
jnz filter
I see you are referring to this session of code. I´ll study your example more carefully and learn from it. But in my case there is no need for a Look up table. The chars to filter are minimum in quantity.
Basically, I´m using the base map to set my game level design and so forth. these marks need to be removed. As an example, I´m marking lines with ">" where my bombers should be set (check out my last exe for the game for the bombers).
">" as a bomber:
Quote@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
All that filtering session is doing is checking for these isolated symbols and change them back to the bk @ one.
I might have not understood you well, please forgive me if I did. I thought a test case should be quite enough for the task
Forgot to say, thanks for the "or"/"test" tip when comparing to 0.
And by the way, in my proggy I´m checking the zero flag very often:
Quotecmp bl, 0
js Negative
jz Zero
jns Positive
I got away with "cmp bl, 0". Should "test" be a better one then? I guess the answer is ...yes..?edit: Self correction: AND does the job nicely
Quote from: LordAdef on March 20, 2017, 02:00:25 PM00
cmp bl, 0
js Negative
jz Zero
jns Positive
print "this is the 4t option", 13, 10
;)
Here is a nice one, the
shr eax, 1 is Copyright DednDave:
lea edi, msg
.While 1
xor eax, eax
invoke GetMessage, edi, eax, eax, eax
inc eax
shr eax, 1
.Break .if Zero? ; 0 (OK) or -1 (error)
invoke TranslateMessage, edi
invoke DispatchMessage, edi
.Endw
hardly a copyright - lol
but, he won't understand the advantage until he has a better understading of the full instruction set
INC EAX is a single-byte instruction, typically taking 1 clock cycle
SHR EAX,1 is a two-byte instruction, also 1 clock
Don't worry, Alex is learning very quickly :P
The clock cycles hardly matter in a GetMessage loop, but it's an elegant way to test for 0 and -1 simultaneously, that's why I posted it here.
include \masm32\include\masm32rt.inc ; plain Masm32
.code
start:
mov ebx, -3
.Repeat
print str$(ebx), 9
mov eax, ebx
inc eax
shr eax, 1
.if Zero?
print "ZERO", 13, 10
.else
print "non-zero", 13, 10
.endif
inc ebx
.Until sdword ptr ebx>2
inkey "ok?"
exit
end start
Output:
-3 non-zero
-2 non-zero
-1 ZERO
0 ZERO
1 non-zero
2 non-zero
This is still my preferred message loop in 32 bit code when you are not processing keystrokes.
MsgLoop proc
LOCAL msg:MSG
push ebx
lea ebx, msg
jmp getmsg
msgloop:
invoke TranslateMessage, ebx
invoke DispatchMessage, ebx
getmsg:
invoke GetMessage,ebx,0,0,0
test eax, eax
jnz msgloop
pop ebx
ret
MsgLoop endp
64 bit version does not look much different.
msgloop proc
LOCAL msg :MSG
LOCAL pmsg :QWORD
mov pmsg, ptr$(msg) ; get the msg structure address
jmp gmsg ; jump directly to GetMessage()
mloop:
invoke TranslateMessage,pmsg
invoke DispatchMessage,pmsg
gmsg:
test rax, rv(GetMessage,pmsg,0,0,0) ; loop until GetMessage returns zero
jnz mloop
ret
msgloop endp
Hello sir LordAdef;
I read some of your sources and look good man, that river raid make me feel nostalgic time. Nice. I perceive that you have programming knowledge, you modeled your data so rle works fine.
On pass 3 you can read a dword data and compare with next dword data, so you need add 4 as displacement, and when they differs you do on byte way to normalize.
edited: I forgot to say, I tested yours examples on wine under linux and worked fine.
Hi Mineiro!!
Thanks a lot!
QuoteI read some of your sources and look good man, that river raid make me feel nostalgic time.
Yes, River Raid was a fantastic game. In order to have a goal, I chose it as a project.
QuoteNice. I perceive that you have programming knowledge, you modeled your data so rle works fine
I do in fact, although I´ve never had a formal education. As most of us, I started with good old BASIC, then I moved onto a couple of other things. I must admit I feel like I wasted my time! Assembly was always something painted as a "don´t touch it" thing. I am in love and I think I will stuck with asm for good.
QuoteOn pass 3 you can read a dword data and compare with next dword data
This is actually a great idea!
I´m currently writing the decompression code to unroll my map back. Almost done! This is the one I need to be fast, since it´s going to be working at runtime in the proggy.
I´m doing it slow but steady. I want to finish this game at all costs.
Hey guys,
After your tips in the other thread, I enclosed the prog now with the rle working fine and faster (decomp.inc, decomp.asm).
Richmasm and Asm files included, although qEditor (not its fault, mine for sure) complaint when building:
QuoteC:\masm32\AFprojs\09_game_test_03\Main.asm(64) : warning A4014: instructions and initialized data not supported in BSS segments
...
LINK : fatal error LNK1181: cannot open input file "C:\masm32\AFprojs\09_game_test_03\Main.obj"
Mineiro, I tried to make a struct for the header (mainly because there are more things to go in there). It slowed it down a bit, I kept it as it was.
I´m also now using "Alloc" in the procedure (sending the address to MapPtr dd ?).
Next, I´m creating an array of pointers to hold the line addresses. That will speed up my paint code and also give me freedom to do my next step with this thing.
Cheers, Alex
Works fine indeed :t
I wonder why it throws a Warning A4184: Instructions and initialized data not supported in BSS segments on
gm Game <>
::)
possibly either the symbol "gm" or "Game" (or both) are defined elsewhere ?
Hey, I got some interesting update on this, and
I think I found a bug in qEditor and that´s why it´s not building.1. Decomp????
Yep, my bad. I left a line of code of this old variable. Here it is the culprit:
Quotemov edi, offset Decomp ====> The little persistent bastard is here!
mov esi, InputFile(string)
mov tLen, ecx
; allocate dest. memory
mov MapPtr, alloc ( DWORD Ptr [esi]) ====> It was replaced by this fellow
mov edi, MapPtr
2. gm Game <>:
Quote
Game STRUCT
lives dd ?
level dd ?
state dd ?
speed dd ?
kills dd ?
mapRect RECT <>
dispRect RECT <>
bomber dd 30 dup(Bomber) <==== HERE. Bomber is a uninitialized struct too.
enemies dd 60 dup(?)
Game ENDS
3. qEditor:
Quote
LINK : fatal error LNK1181: cannot open input file "C:\masm32\AFprojs\09_game_test_03\Main.obj"
Link error
=> It
doesn´t build when you "Windows Explorer->Main.asm->rightClick->open in qEditor"
=> It builds fine when you open the file from within qEditor
Please try and replicate this issue, so to confirm it to Hutch
i'm a little rusty, but i think it should be...
bomber dd 30 dup(Bomber<>)
something like that
Yes, thanks!
Did you replicate the qEditor thing?
i don't use qEditor - lol
Quote from: LordAdef on March 31, 2017, 06:18:49 AM=> It builds fine when you open the file from within qEditor
Builds fine with RichMasm, and builds OK when I drag Main.asm over qEditor.exe - but qEditor ignores the resources for some reason.
The default MASM32 console build requires the resource script to be called RSRC.RC. Added a "makeit.bat" and renamed the RC script and it builds as normal in QE using the MASM32 default.
Hi guys,
It´s been a while I don´t update this project, so here I am.
It´s not optimized "at all". There are many decouplings to fix and CPU is running hot for now. But all in all this begins to look like a game.
1. My rle is working in all its glory (thanks everyone for helping optimizing it)
2. I made some game management already, so it loads levels, reset level when we die and so forth...
3. Fuel is working now (not refueling)
4. There are 3 temporary maps so I can test things
5. Made a experimental explosion. Try and suicide, and check it out. It´s quite nice :D
6. Maps are way larger now. I decompress them, but in fact I use an array of pointers. This way I´m doubling its lenght, but reversing it in the second half. More content for the same space
7. Collision Detection is in place, but in pure bare bones, only for development.
8. Made some "god mode" keys for development:
number 1: resume game
number 2: pause game
number 4: load next level
9. arrows work as usual, however I limited to only 2 speeds for now.
10. Built with RichMasm. This time I didn´t try on qEditor, but I know it gives it errors. I didn´t try to fix them though
Cheers, Alex
Hi LordAdef,
The arrow keys are not responding.
EDIT: it works now, had to press 1 first. :t
Just a fixed map, with the airplane and a copyright symbold instead the bombarder of previous versions.
try number 1 to resume game, it starts in pause mode
press 2 and it pauses.
if you press 4 "while" running, it loads the next level
Beautifull ... crash using 1
The code is not ML compatible. For this I used AsmC:
004014F5 > 55 PUSH EBP
004014F6 8BEC MOV EBP, ESP
004014F8 A1 8CD14000 MOV EAX, DWORD PTR DS:[man]
004014FD 83E8 62 SUB EAX, 62
00401500 BB 05000000 MOV EBX, 5
00401505 F7F3 DIV EBX <--- CRASH
00401507 8B3D 78544000 MOV EDI, DWORD PTR DS:[405478]
0040150D 83C7 3C ADD EDI, 3C
00401510 8B34BD 8C544000 MOV ESI, DWORD PTR DS:[EDI*4+40548C]
00401517 03F0 ADD ESI, EAX
00401519 803E 40 CMP BYTE PTR DS:[ESI], 40
0040151C 74 02 JE SHORT Main_v8_.00401520
0040151E EB 08 JMP SHORT Main_v8_.00401528
00401520 FF75 08 PUSH DWORD PTR SS:[EBP+8]
00401523 E8 E1090000 CALL Main_v8_.pDead
00401528 5D POP EBP
00401529 C2 0400 RETN 4
JWasm.
I'll check it out for compatibility. Cheers
Wow, how fast is it. Only one thing, if you press to the left or to the right, the plane keep on facing to there though you release the key.
Quote from: caballero on April 25, 2017, 04:56:31 AM
Wow, how fast is it. Only one thing, if you press to the left or to the right, the plane keep on facing to there though you release the key.
Hi Caballero! wow, this is totally unexpected... It's a simple KeyUp message that brings the plane back to the right position... I'm turning the pc on and see what's happening. Please follow me on this.
Anyone else not having the plane back to straight position?
Works fine here, no problems with these keys. You might write in big letters "press 1 to start the game", it took me a while to find that out :P
Quote from: LordAdef on April 24, 2017, 10:43:04 PMTry and suicide, and check it out. It´s quite nice :D
Try posting such a phrase in a forum for kids & education, the mums will eat you alive :badgrin:
QuoteTry posting such a phrase in a forum for kids & education, the mums will eat you alive :badgrin:
hahaha.. you are right! Out of context this line sounds indeed quite odd
HI there,
A quick update:
1. It now shows "Press 1 to start"
2. Caballero had and issue with the plane not returning to straight position. This should be fixed now (I hope :badgrin:)
Caballero, let me know?
It´s still not currently ml compatible. I´ll be working on that. Nevertheless, I placed the main source code as an asm file for reference only.
Works fine here, also no problems with these keys.
Quote from: Siekmanski on April 25, 2017, 10:30:24 PM
Works fine here, also no problems with these keys.
Thanks Marinus!
Btw, sometime in the far future I will need to add music... I am surely bothering you when the time comes, I'd love some contribution from you.
I already have a friend from the place I work that will be doing the graphics for the final build
It works fine now :)
Commenting pColisionDetection work without problem!
Not working on XP (crashes after pressing 1)
Quote from: guga on April 26, 2017, 12:11:23 AM
Not working on XP (crashes after pressing 1)
sub eax, 98
cdq ; and it works in XP...
m2m ebx, 5
div ebx ; eax is char count in line
Perfect JJ :t
Quote from: LordAdef on April 25, 2017, 11:04:59 PM
Thanks Marinus!
Btw, sometime in the far future I will need to add music... I am surely bothering you when the time comes, I'd love some contribution from you.
I already have a friend from the place I work that will be doing the graphics for the final build
I hope you don't mean to compose music, that will be a total disaster. :lol:
I think you meant some music replay routines.
QuoteI hope you don't mean to compose music, that will be a total disaster. :lol:
I think you meant some music replay routines.
Don´t worry, I can handle the music. I´m a music composer (or I think I am)
Quotesub eax, 98
cdq ; and it works in XP...
m2m ebx, 5
div ebx
Thanks for that JJ.
So XP complained and needed sign extension. Would you tell me why win7 was ok while XP was not?
One more question if I may: I thought I should be fine as I was doing unsigned values. Should I always CWB/CWD/CQD to avoid such conflicts?
And thanks everyone for the help!!
Hi,
So, I was checking the ml compatibility and found only 2 places where things go bad in ml:
1. In main.asm (Line 431), the IF statement within a Switch-Case:
Quotemain.asm(434) : error A2206: missing operator in expression
main.asm(437) : error A2206: missing operator in expression
main.asm(439) : error A2206: missing operator in expression
main.asm(440) : error A2206: missing operator in expression
The problematic code for ml (comment and ther errors are gone):
QuoteSwitch gm.state
Case PLAYLEVEL, STANDBY
;-------------- GODs MODE KEYS -------------
.IF wParam == 0x31 ; key "1" start timers
mov gm.state, PLAYLEVEL
invoke pSetTimer_All, hWnd
.ELSEIF wParam == 0x32 ; key "2" stop timers
invoke pKillTimer_All, hWnd
.ELSEIF wParam == 0x33 ; key "3" empty
.ELSEIF wParam == 0x34 ; key "4" load new level
m2m gm.state, LEVELDONE
.ENDIF
endsw
In Decomp.inc, these const:
Quotedecomp.inc(46) : error A2042: statement too complex
decomp.inc(51) : error A2008: syntax error : integer
decomp.asm(175) : error A2006: undefined symbol : statBlockage1
decomp.asm(175) : error A2114: INVOKE argument type mismatch : argument : 2
decomp.asm(174) : error A2006: undefined symbol : statBlockage1
decomp.asm(184) : error A2006: undefined symbol : statBlockage1
(commenting, leaving few vars and you get no errors.)
QuotestatMines1 dd 137782, 138577, 138899, 141944, 142110, 151425, 151919, 152373, 152569, 153499,\
153974, 154131, 154289, 190342, 192719, 192878, 194344, 194345
statBlockage1 dd 186986, 186987, 186988, 186989, 186990, 186991, 186992, 186993, 186994, 186995,\
186996, 186997, 186998, 186999, 187000, 187001, 187002, 187003, 187004, 187005,\
187006, 187007, 187008, 187009, 187010, 187011, 187012, 187013, 187014, 187015,\
187016, 187146, 187147, 187148, 187149, 187150, 187151, 187152, 187153, 187154,\
187155, 187156, 187157, 187158, 187159, 187160, 187161, 187162, 187163, 187164,\
187165, 187166, 187167, 187168, 187169, 187170, 187171, 187172, 187173, 187174,\
187175, 187176
statFuel2 dd 8867, 48448, 59781, 65220, 68562, 72358, 75612, 81510, 87119, 89510
statMines2 dd 1000
statBlockage2 dd 1000
In short, I´m ml compatible except from these 2 things: the .IF statement and those variables declarations.
HJWasm is ok and gives me no warnings.
ps: makeit.bat in zip was kindly provided by Hutch
deleted
Quote from: LordAdef on April 27, 2017, 01:59:17 AMSo XP complained and needed sign extension. Would you tell me why win7 was ok while XP was not?
edx is undefined when you return from whatever WinAPI call. And the API changes with every Windows version. Not the
documented behaviour, of course - that is remarkably stable. But ecx and edx can contain any value (MB preserves ecx, though).
So if you got, by accident, 0 in edx when running it in Win7, the div ebx works fine. But XP has a different edx, and bang :(
The solution is simple: every div MUST be preceded by cdq, except for the rare case when you really want to divide a edx::eax QWORD.
@nidud: you were almost one minute faster ;)
Caution with xor edx, edx: This assumes that eax is positive; OK most of the time, but with idiv you get unexpected results:
include \masm32\MasmBasic\MasmBasic.inc ; download (http://masm32.com/board/index.php?topic=94.0)
Init
mov eax, -111
xor edx, edx
mov ecx, 3
idiv ecx
deb 4, "result", eax
mov eax, -111
cdq
mov ecx, 3
idiv ecx
deb 4, "result", eax
Inkey
EndOfCodeOutput:
result eax 1431655728
result eax -37
Besides, cdq is one byte shorter than xor edx, edx ;)
I'm thinking gm.state is the problem because ml need OPTION DOTNAME to allow that point. I can't test it, but now is working perfect with others assemblers.
Dots are OK for structures. The problem was elsewhere:
- ML has a maximum line length
- ML does not support 0x12 syntax
Attached a slightly corrected version.
Thanks HSE and JJ,
Yep, dot notation is fine. I´ve always tested for ml compatibility and from time to time I bump into something. But dot notation has been there for a long time, ml was fine with that.
In fact, I find this compatibility thing quite instructive. I´m using RichMasm/HJWasm, but I´m trying to keep the compatibility so I can share the code here in the forum.
Not meaning to start a war here, but I notice JWasm is more tolerant in many places, such as this 0x32 notation and the line limit I crossed and JJ pinpointed. But they are close enough not to be a big deal.
I´m not sure if there is a feature comparison available. That would be interesting.
Quote from: LordAdef on April 27, 2017, 08:36:10 PMI´m not sure if there is a feature comparison available.
Well, kind of (http://www.masmforum.com/board/index.php?topic=9835.0) :P
For MasmBasic fans, here a special feature of ML:
include \masm32\MasmBasic\MasmBasic.inc ; download (http://masm32.com/board/index.php?topic=94.0)
Init
mov esi, Chr$("This is a hello World string")
xor ecx, ecx
xor edx, edx
mov eax, [ecx+edx+esi+10] ; three register addressing!
push 0
push eax
deb 1, "Test", $esp
pop edx
pop eax
EndOfCode
OPT_Assembler ML ; use Microsoft MASMNote you
must force ML because HJWasm is not yet enabled for three register addressing mode (Habran and Johnsa are working on it).
Here is the 64-bit version:
include \Masm32\MasmBasic\Res\JBasic.inc
.data
buffer db "Just a test", 0
Init ; OPT_64 1 ; 64 bit assembly
PrintLine Chr$("This code was assembled with ", @AsmUsed$(1), " in ", jbit$, "-bit format")
mov rsi, Chr$("This is a hello World string")
xor ecx, ecx
xor edx, edx
mov rax, [rcx+rdx+rsi+10] ; three register addressing!
lea rdx, buffer
usedeb=1
mov [rdx], rax
deb 1, "Test", $rdx
EndOfCode
OPT_Assembler ML ; use the latest and best version of Microsoft MASM
Output:
This code was assembled with ml64 in 64-bit format
Test $rdx hello Woest
deleted
deleted
Quote from: nidud on April 27, 2017, 11:12:49 PM
hello.asm(20) : error A2030: multiple index registers not allowed
Yes, ML 6.14 and 6.15 throw errors. Microsoft introduced this feature in ML version 8.0 and higher. As my 64-bit example above demonstrates, it builds fine in ML64 (a bit slow, perhaps - 15 seconds), even with version 14:
Microsoft (R) Macro Assembler (x64) Version 14.00.24210.0
Copyright (C) Microsoft Corporation. All rights reserved.
*** Link Skel_GccVc.obj using polink, sub CONSOLE /entry:start- no resources ***
Creating object: Tmp_File.exp
Creating library: Tmp_File.lib
*** build all took 15522 ms ***
Rumours say that Intel and AMD are not happy that M$ allows coders to use this feature 8)
deleted
> mov eax, [ebx+eax+ecx+edx+esi+10]
Yep, that is the right spirit :t
Let's push the cpu to its limits:
lea rdx, [rcx+rdx+rsi+r8+r9+r10+r11+r12+10] ; eight register addressing!
Works fine, and builds in less than fifteen seconds:Microsoft (R) Macro Assembler (x64) Version 14.00.24210.0
Copyright (C) Microsoft Corporation. All rights reserved.
*** Link SkelMbEmpty.obj using polink, sub CONSOLE /entry:start- no resources ***
Creating object: Tmp_File.exp
Creating library: Tmp_File.lib
*** build all took 14992 ms ***
deleted
I am sure johnsa and habran are aware of their responsibilities. These new Microsoft features must be implemented asap 8)
[ok ok, this is The Campus, therefore, message to all n00bs readings this: do not believe everything that is written on this forum! Most of us are human beings, we are stupid or ignorant at times, and we see it as our moral obligation to pull your legs. Bashing Micros**t for their incredible bugs is our responsibility, too, and we take that very seriously :eusa_boohoo:]
:biggrin:
You know the magic MASM rule, its not a bug, its a feature you need to understand. Unless Intel have sneaked an undocumented capacity that nobody knew about,multiple index's don't have a matching opcode so they don't fly. RE : MASM error checking, it is more often than not unintelligible nonsense, its a tool written for people who know NOT to try and invent opcodes of their own. If they do they get garbage on the screen.
MASM has always had the answer to fast reliable code, write it with no errors and it will run properly, if not go back and learn how to write code with no errors. :P
Quotelea rdx, [rcx+rdx+rsi+r8+r9+r10+r11+r12+10] ; eight register addressing!
ok, I'm working and couldn't follow the last page well... Does this aberration actually works?
deleted
Quote from: LordAdef on April 28, 2017, 09:01:13 AMDoes this aberration actually work?
Yes and no:
int 3
lea rdx, [rcx+rdx+rsi+r8+r9+r10+r11+r12+10] ; eight register addressing!
x64dbg:
00000001400011E5 | CC | int3 |
00000001400011E6 | 4B 8D 54 1C 0A | lea rdx, qword ptr ds:[r12+r11+A] |
So ML64 uses the last two registers r12, r11 for the encoding (hex A=dec 10). It "works" if these two registers contain meaningful values. But of course, a good assembler
must throw an "invalid opcode" error. It's a fat Micros**t bug, nothing else.
Guys, what do you think?
I´m tweaking the engine and like your opinion. I made some tests using a Double Buffer, instead of doing straight to HDC:
(all in WM_PAINT)
1. Main_Current: I´m printing everything to HDC
2. Main_MapDoubleBuffer: Using a Double Buffer where I only paint the bk map. The rest is still going straight to HDC (It´s the middle groung between the 2 others)
3. Main_All_in_DoubleBuffer: Everything is built in the Back Buffer.
All 3 options attached. Asm file compatible with ml, although my resources are not being joined (I don´t know why, pure ignorance of mine really)
There is a trade here:
-> Main_Current is faster, but flickers
-> All_in_DoubleBuffer is the fastest of the two using double buffer (curiously). Although I´m slower, the feel is more solid, since the image is less flickery.
Would you trade the speed of #1 for visual stability of #3? I inclined to do it.
My benchmarks:
QuoteEverything straight to HDC:
6458 us 6505 us 6544 us 6686 us 6454 us 6362 us 6433 us 6392 us 6306 us 6448 us 6390 us 6447 us 6544 us 6481 us 6899
ONly BK map is sent to Back Buffer, the rest is straight to HDC
7638 us 7766 us 7531 us 7544 us 7531 us 7581 us 7583 us 7596 us 7799 us 7729 us 7787 us 7711 us 7894 us 7698 us 7545
All to Back Buffer
7208 us 7151 us 7344 us 7215 us 7248 us 7112 us 7238 us 7384 us 7279 us 7258 us 7339 us 7165 us 7266 us 7265 us 7285
Cheers Alex
I've downloaded all three, and can't find any difference in speed. And all three flicker, not much but equally ::)
This is on Win7-64 and a Core i5 cpu.
Quote from: jj2007 on April 29, 2017, 06:17:23 PM
I've downloaded all three, and can't find any difference in speed. And all three flicker, not much but equally ::)
This is on Win7-64 and a Core i5 cpu.
Any suggestion JJ?
.IF uMsg==WM_CREATE
invoke pIniFonts, hdc
mCreateDC
Suggestion: Put all that stuff into the same file, it would be much easier to find it and understand what it does (select the word, hit F3).
More concretely: hdc is a local variable, i.e. it may contain anything. What are you passing to pIniFonts?
Quote from: jj2007 on April 30, 2017, 01:57:13 AM
.IF uMsg==WM_CREATE
invoke pIniFonts, hdc
mCreateDC
Suggestion: Put all that stuff into the same file, it would be much easier to find it and understand what it does (select the word, hit F3).
More concretely: hdc is a local variable, i.e. it may contain anything. What are you passing to pIniFonts?
Ok, checking it out in 10 minutes.
Concerning the paint engine, do you think implementing a new test with the "scroll" Windows function would give me a better flickerless result? A quick test has shown me it may be the case, although the logic imposes some difficulties
ScrollWindow must use BitBlt internally, I doubt that it can be much faster.
I am too busy (and too tired) to look into the double buffering, Alex - but if it's done correctly, it should not flicker at all. For comparison, try sizing the Gdi+ example in File/New Masm source; the only item that flickers is the yellow box in the lower right...
Re pIniFonts:
004023A8 ³. 50 push eax ; ÚhObject
004023A9 ³. FF75 08 push dword ptr [ebp+8] ; ³hDC => [Arg1]
004023AC ³. E8 E7010000 call <jmp.&gdi32.SelectObject> ; ÀGDI32.SelectObject
Returns 0, invalid handle.
I understand JJ, no worries.
Double buffering is not flickering for me. For scrolling, I even think it gets a worse result than compared to double buffering. the three exes in the zip.
QuotepIniFonts proc hdc:DWORD
;----------------------------------------- MAP FONT -----------------------------------------------------------------------------------------------------------
invoke CreateFont,12,0,0,0,400,0,0,0,OEM_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,\
DEFAULT_QUALITY,DEFAULT_PITCH or FF_SCRIPT, chr$("Courier New") ;ADDR FontName1 ;Lucida Console
mov Font1, eax
invoke SelectObject, hdc, eax
mov OldFont, eax
;---------------------------------------- MAN FONT -----------------------------------------------------------------------------------------------------------
invoke CreateFont,18,0,0,0,400,0,0,0,OEM_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,\
DEFAULT_QUALITY,DEFAULT_PITCH or FF_SCRIPT, chr$("Arial")
mov Font2, eax
;---------------------------------------- LABEL FONT --------------------------------------------------------------------------------------------------------
invoke CreateFont,52,0,0,0,400,0,0,0,OEM_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,\
DEFAULT_QUALITY,DEFAULT_PITCH or FF_SCRIPT, chr$("Arial Black")
mov Font3, eax
;---------------------------------------- LABEL FONT 2 -----------------------------------------------------------------------------------------------------
invoke CreateFont,28,0,0,0,400,0,0,0,OEM_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,\
DEFAULT_QUALITY,DEFAULT_PITCH or FF_SCRIPT, chr$("Arial")
mov Font4, eax
;---------------------------------------- TEST FONT -----------------------------------------------------------------------------------------------------
invoke CreateFont,12,0,0,0,400,0,0,0,OEM_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,\
DEFAULT_QUALITY,DEFAULT_PITCH or FF_SCRIPT, chr$("MapTst")
mov Font5, eax
ret
pIniFonts endp
I´m only using hdc to retrieve the default font, and restore it back when I´m done.
invoke SelectObject, hdc, eax
mov OldFont, eax
I made it as a proc but it was previously sitting in there.
Quote from: LordAdef on April 30, 2017, 05:52:34 AM
I´m only using hdc to retrieve the default font, and restore it back when I´m done.
invoke SelectObject, hdc, eax
int 3
mov OldFont, eax
If Olly (http://www.ollydbg.de/version2.html) is installed as \Masm32\OllyDbg\ollydbg.exe, hit F6 and have a look at eax and the error message.
Otherwise,
- activate MasmBasic.inc
- OxPT_Susy (disactivates the option, console will be default)
- fonts.asm, line 7:
invoke SelectObject, hdc, eax
ifdef MbBufferGet
fdeb 4, "SelObj", eax, hdc, $Err$()
endif
mov OldFont, eax
A quick help, please...
I need to iterate through an array of structures. [ebx*Bullet ] wont do it, but [2*Bullet] does. Pre compile thing? How do I do this?
xor ecx, ecx
@@:
mov edi, offset man.bullets[ecx*Bullet].active
.IF dword Ptr [edi] == 1
printf (" Bullet %d is active\n", dword Ptr [edi])
.ENDIF
inc ecx
cmp ecx, 100
jnz @B
QuoteBullet STRUCT
active dd ?
speed dd ?
x dd ?
y dd ?
Bullet ENDS
Player STRUCT
align 4
x dd ?
y dd ?
sprite dd ?
frmx dd ?
frmy dd ?
bullets Bullet 100 dup (<>) <==== These guys HERE
kState dd ?
Player ENDS
QuoteIf Olly is installed as \Masm32\OllyDbg\ollydbg.exe, hit F6 and have a look at eax and the error message.
Thanks, I´ll have a look
Hi Alex,
Maybe ebx/ecx is trashed by the function "printf" ?
try this,
mov edi,offset Player.bullets
mov esi,0
find_active_bullets:
.if dword ptr[edi].Bullet.active == 1
printf (" Bullet %d is active\n", esi)
.endif
add edi,sizeof Bullet
inc esi
cmp esi, 100
jne find_active_bullets
little hint: you can align the struct to 4 like this,
Player STRUCT 4
Quote from: LordAdef on April 30, 2017, 10:17:59 AM
A quick help, please...
I need to iterate through an array of structures. [ebx*Bullet ] wont do it, but [2*Bullet] does. Pre compile thing? How do I do this?
xor ecx, ecx
@@:
mov edi, offset man.bullets[ecx*Bullet].active
.IF dword Ptr [edi] == 1
printf (" Bullet %d is active\n", dword Ptr [edi])
.ENDIF
inc ecx
cmp ecx, 100
jnz @B
Marinus is right, ecx gets trashed - MB Print Str$() preserves ecx, but printf() doesn't. Simple solution:
.IF dword Ptr [edi] == 1
push ecx
printf (" Bullet %d is active\n", dword Ptr [edi])
pop ecx
.ENDIF
Btw no need for edi - this should work, too (not tested):
.IF man.bullets[ecx*Bullet].active == 1
push ecx
printf (" Bullet 1 is active\n") ; 1 is it's value, for sure, so a constant will do ;-)
pop ecx
.ENDIF
Thanks Marinus and JJ,
But ecx being trash is not the point. The point is my clause with a register is not building.
A test bed:
Quoteinclude \masm32\include\masm32rt.inc
Bullet STRUCT
active dd ?
speed dd ?
x dd ?
y dd ?
Bullet ENDS
Player STRUCT 4
x dd ?
y dd ?
sprite dd ?
frmx dd ?
frmy dd ?
bullets Bullet 50 dup (<>)
kState dd ?
Player ENDS
.data
man Player <>
.code
start:
mov man.bullets[2*Bullet].active, TRUE
mov man.bullets[2*Bullet].speed, 100
mov man.bullets[2*Bullet].x, 100
mov man.bullets[2*Bullet].y, 100
mov eax, 2
;mov man.bullets[2*Bullet].active, FALSE ; <== THIS WORKS
mov man.bullets[eax*Bullet].active, FALSE ; <== THIS DOESN´T
invoke ExitProcess, eax
end start
This is the problem:
Quote;mov man.bullets[2*Bullet].active, FALSE ; <== THIS WORKS
mov man.bullets[eax*Bullet].active, FALSE ; <== THIS DOESN´T
Marinus, thanks for the align trick! Does this automatically align all items in the struct?
Quote from: LordAdef on May 01, 2017, 08:07:39 AM
Marinus, thanks for the align trick! Does this automatically align all items in the struct?
No, only the struct is aligned, but you can use align xx wihtin a struct or place a dummy byte.
this should work,
mov esi,offset man.bullets
mov ecx,sizeof Bullet
mov eax,2 ; the bullet number
mul ecx
mov dword ptr [esi+eax].Bullet.active,FALSE
edit:
Or in this case because the Bullet struct is 16 bytes,
mov esi,offset man.bullets
mov eax,2 ; the bullet number
shl eax,4
mov dword ptr [esi+eax].Bullet.active,FALSE
Inside brackets you only can multiply by 2,4,8,...
Quote from: HSE on May 01, 2017, 08:52:06 AM
Inside brackets you only can multiply by 2,4,8,...
But this works fine:
mov man.bullets[3*Bullet].active, TRUE ; <== THIS WORKS
And eax in the test bed was == 2.
edit:
It works fine with a constant. Is this a pre-compiling thing?
Quote.const
cINDEX EQU 3
...
mov man.bullets[cINDEX*Bullet].active, TRUE ; <== THIS WORKS
Maybe because its an invalid scale value ?
Marinus,
QuoteNo, only the struct is aligned, but you can use align xx wihtin a struct or place a dummy byte.
this should work,
It sure works. However, I wished I could use that syntax, or at least understand why it´s not working
QuoteMaybe because its an invalid scale value ?
Sure, but in this case
mov man.bullets[3*Bullet].active, TRUE shouldn´t work either
does this work ?
mov eax,2 ; the bullet number
shl eax,4
mov man.bullets[eax].active, FALSE
what assembler do you use ?
Quote from: LordAdef on May 01, 2017, 08:54:59 AM
It works fine with a constant. Is this a pre-compiling thing?
Exactly:
At compile time, any constant is fine.
At runtime, HSE's remark is correct: 2, 4 or 8 are the allowed scaling values.
Quote from: Siekmanski on May 01, 2017, 09:12:46 AM
does this work ?
mov eax,2 ; the bullet number
shl eax,4
mov man.bullets[eax].active, FALSE
what assembler do you use ?
That works too.
I´m on HJWasm, since I usually use RichMasm. I try and keep compatibility using qEditor (ML)
QuoteAt compile time, any constant is fine.
At runtime, HSE's remark is correct: 2, 4 or 8 are the allowed scaling values.
I was suspecting that, and the constant test showed it. So, in that syntax the compiler can´t know the value of the register and thus generates an error. Got it.
Thanks everyone, this was instructive.
Quote from: LordAdef on May 01, 2017, 09:49:33 AMI´m on HJWasm, since I usually use RichMasm. I try and keep compatibility using qEditor (ML)
This is how I test different assemblers:
; OPT_Assembler ML ; somewhere in the file forces RichMasm to use \Masm32\bin\ml.exe (or any other exe...)
OPT is case-sensitive, the rest isn't.
Just put an x after the O: O
xPT_anyoption to disable an option. If there are several options of the same type, the last one is valid:
...
end start
OPT_Arg1 fileA.txt
OPT_Arg1 fileB.txt
CL$() (http://www.webalice.it/jj2006/MasmBasicQuickReference.htm#Mb1011) will find fileB.txt
NICE ONE!!!!! RM/MB always have a away around things..
Something that some folks miss, a "syntax error" with an instruction means that the processor does not have a matching opcode for something in source code that has been fed to it. This applies to the multiplier range of 2, 4 and 8, each of which has a matching opcode, try it with any other number and you are trying to call a non existent opcode. The assembler "should" catch this but they can be a bit sloppy and miss a simple error like this, an error type the is mainly a typo.