News:

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

MasmBasic

Started by jj2007, October 06, 2009, 08:24:57 PM

Previous topic - Next topic

dedndave

it is strange - lol
microsoft hasn't documented this thing very well   :P

jj2007

For those who use the MakeFont macro: There is a bug in line 1260 of \masm32\MasmBasic\MasmBasic.inc - pop edi instead of pop esi
It will be fixed in the next update.

push esi
push edi
mov esi, offset fontname
lea edi, [edx+LOGFONT.lfFaceName]
push SIZEOF fontname
pop ecx
rep movsb
pop edi
pop esi ; <<<<<<<<<<<<<<<

jj2007

Just for fun, here an example how C and MasmBasic can be mixed. Output:
25+35=          60
25*4=           100
(25+35)*10=     600
123=            123

Quoteinclude \masm32\include\masm32rt.inc   ; inspired by Vortex (Erol) 28.8.2006
include ImportC.inc

ImportC jjSum, 2   ; sums up x+y
ImportC jjMult, 2   ; multiplies x with y
ImportC jjXyz, 3   ; sums up x+y, then multiplies result with z
ImportC jjNoArgs, 0   ; accepts no args and returns always 123

.code
start:   mov ebx, esp      ; little check if the stack is OK after using these C functions

   print "25+35=    ", 9
   invoke jjSum, 25, 35
   print str$(eax), 13, 10

   print "25*4=    ", 9
   invoke jjMult, 25, 4
   print str$(eax), 13, 10

   print "(25+35)*10=", 9
   invoke jjXyz, 25, 35, 10
   print str$(eax), 13, 10

   print "123=    ", 9
   invoke jjNoArgs
   print str$(eax), 13, 10

   print "Stack test:", 9
   sub ebx, esp
   .if Zero?
      inkey "OK"
   .else
      inkey str$(ebx)
   .endif
   exit
end start

RichMasm options:
extra option for linker:
OPT_DebugL   jjCalc.obj
extra commandline before assembly:
OPT_BatA   "%ProgramFiles%\Microsoft Visual Studio 9.0\VC\bin\cl.exe" /c /Oty2 /Zl /Gs /GS- /FojjCalc.obj /Fa jjCalc.cpp

Here the utterly sophisticated C program:
extern "C"
int _stdcall jjMult(int x , int y)
{
  return(x*y);
}

extern "C"
int _stdcall jjSum(int x , int y)
{
  return(x+y);
}

extern "C"
int _stdcall jjXyz(int x, int y, int z)
{
  return((x+y)*z);
}

extern "C"
int _stdcall jjNoArgs()
{
  return(123);
}


The ImportC macro (attached) will become part of the next MasmBasic release.

jj2007

Minor change in \masm32\MasmBasic\MasmBasic.inc, line 3816:

Old:
wLet MACRO args
  MbWideLet = 1024
  % Let args   ; JWasm needs the %
ENDM

New:
wLet MACRO args
  MbWideLet = 1024
  Let args   ; JWasm needed a %
ENDM

Make sure you use JWasm version 2.05 or higher.

jj2007

Following a discovery that Masm32 CombSortA fails with certain FPU settings, I rewrote a new algo for MasmBasic. It is slightly faster than CombSortA, slightly slower than nrQsortA, and handles both ascending and descending sort in the same routine (i.e. the code size is twice as good as it seems because the Masm32 variants need 2* their size for ascending + descending).

The algo will be added to the next release, but some timings would be welcome.


Intel(R) Celeron(R) M CPU        420  @ 1.60GHz (SSE3)
1293963 cycles for nrQsortA
1603816 cycles for CombSortA
1459890 cycles for MbCombSort

Items:  10000
198      bytes for nrQsortA
112      bytes for CombSortA
123      bytes for MbCombSort

Prescott P4 timings:
Items:  10000
2821448 cycles for nrQsortA
3350106 cycles for CombSortA
2316684 cycles for MbCombSort

2158186 cycles for nrQsortA
2476503 cycles for CombSortA
2564312 cycles for MbCombSort

2127466 cycles for nrQsortA
2650659 cycles for CombSortA
3063289 cycles for MbCombSort


aker

C:\Libya>MasmBasicSort.exe
Genuine Intel(R) CPU           T2400  @ 1.83GHz (SSE3)
0 errors for nrQsortA
0 errors for ShakeSort
0 errors for CombSortA
0 errors for MbCombSort
0 errors for MbCombSort

Items: 10000
Masm32:
11      3.000000e+20
10      3000.000
9       123.4560
8       100.0010
7       99.99900
6       99.00000
5       1.000001
4       1.000000
3       0.9999990
2       3.000000e-20
1       0.0
0       -3000.000

JJ up:
11      3.000000e+20
10      3000.000
9       123.4560
8       100.0010
7       99.99900
6       99.00000
5       1.000001
4       1.000000
3       0.9999990
2       3.000000e-20
1       0.0
0       -3000.000

JJ down:
11      -3000.000
10      0.0
9       3.000000e-20
8       0.9999990
7       1.000000
6       1.000001
5       99.00000
4       99.99900
3       100.0010
2       123.4560
1       3000.000
0       3.000000e+20

More?

1339651 cycles for nrQsortA
1653383 cycles for CombSortA
1492463 cycles for MbCombSort

1347008 cycles for nrQsortA
1629444 cycles for CombSortA
1501308 cycles for MbCombSort

1341482 cycles for nrQsortA
1656582 cycles for CombSortA
1514172 cycles for MbCombSort

1318246 cycles for nrQsortA
1646944 cycles for CombSortA
1517919 cycles for MbCombSort

1347515 cycles for nrQsortA
1641691 cycles for CombSortA
1499894 cycles for MbCombSort

1335777 cycles for nrQsortA
1663117 cycles for CombSortA
1508589 cycles for MbCombSort

1318036 cycles for nrQsortA
1639635 cycles for CombSortA
1484425 cycles for MbCombSort


Items:  10000
198      bytes for nrQsortA
112      bytes for CombSortA
123      bytes for MbCombSort

--- ok ---

C:\Libya>
伟大的恐怖主义革命家拉登,因遭袭医治无效,于2011年5月1日在巴基斯坦逝世,享年54岁

six_L

QuoteIntel(R) Core(TM) i3 CPU         550  @ 3.20GHz (SSE4)
0 errors for nrQsortA
0 errors for ShakeSort
0 errors for CombSortA
0 errors for MbCombSort
0 errors for MbCombSort

Items: 10000
Masm32:
11   3.000000e+20
10   3000.000
9   123.4560
8   100.0010
7   99.99900
6   99.00000
5   1.000001
4   1.000000
3   0.9999990
2   3.000000e-20
1   0.0
0   -3000.000

JJ up:
11   3.000000e+20
10   3000.000
9   123.4560
8   100.0010
7   99.99900
6   99.00000
5   1.000001
4   1.000000
3   0.9999990
2   3.000000e-20
1   0.0
0   -3000.000

JJ down:
11   -3000.000
10   0.0
9   3.000000e-20
8   0.9999990
7   1.000000
6   1.000001
5   99.00000
4   99.99900
3   100.0010
2   123.4560
1   3000.000
0   3.000000e+20

More?

1235063   cycles for nrQsortA
1360410   cycles for CombSortA
1283783   cycles for MbCombSort

1226742   cycles for nrQsortA
1371924   cycles for CombSortA
1305272   cycles for MbCombSort

1236347   cycles for nrQsortA
1385884   cycles for CombSortA
1306424   cycles for MbCombSort

1228710   cycles for nrQsortA
1361012   cycles for CombSortA
1298305   cycles for MbCombSort

1253573   cycles for nrQsortA
1371595   cycles for CombSortA
1306666   cycles for MbCombSort

1270989   cycles for nrQsortA
1378449   cycles for CombSortA
1302128   cycles for MbCombSort

1228358   cycles for nrQsortA
1361976   cycles for CombSortA
1302989   cycles for MbCombSort


Items:   10000
198    bytes for nrQsortA
112    bytes for CombSortA
123    bytes for MbCombSort

--- ok ---

regards

jj2007

Thanks a lot, Aker and six_L.

The new function called ArraySort is now implemented in the 6 April 11 release attached to the thread's top post.
Here are some timings comparing it to the Masm32 library functions; the latter do not handle Real4 arrays, so I added a Dword example. Here, ArraySort is 1-2% slower than CombSortA, although I saw it 6% faster in a different but more complex setting. The Masm32 quicksort is faster for high element counts, but below about 2,000 elements, the comb sorts are faster. Note "cycles per element" refers to the average of all 4 algos.

Intel(R) Celeron(R) M CPU        420  @ 1.60GHz (SSE3)
100000 array elements:
15359   kCycles for ArraySort, Real4
13244   kCycles for ArraySort, Dword
12973   kCycles for CombSortA, Dword
9093    kCycles for nrQsortA,  Dword
130 cycles per element

20000 array elements:
2191    kCycles for ArraySort, Real4
2133    kCycles for ArraySort, Dword
2062    kCycles for CombSortA, Dword
1709    kCycles for nrQsortA,  Dword
104 cycles per element

4000 array elements:
341     kCycles for ArraySort, Real4
331     kCycles for ArraySort, Dword
310     kCycles for CombSortA, Dword
313     kCycles for nrQsortA,  Dword
83 cycles per element

800 array elements:
51      kCycles for ArraySort, Real4
49      kCycles for ArraySort, Dword
46      kCycles for CombSortA, Dword
57      kCycles for nrQsortA,  Dword
66 cycles per element

160 array elements:
8       kCycles for ArraySort, Real4
7       kCycles for ArraySort, Dword
6       kCycles for CombSortA, Dword
10      kCycles for nrQsortA,  Dword
53 cycles per element

32 array elements:
1       kCycles for ArraySort, Real4
1       kCycles for ArraySort, Dword
1       kCycles for CombSortA, Dword
2       kCycles for nrQsortA,  Dword
49 cycles per element

jj2007

... unless your sort algo takes care of the original order, too, so that you can keep track of the records.

Here is a simple example: Results of a 100 m sprint are ordered alphabetically by the boys' names. Simply sorting the REAL4 variables in Times100 would lead to nowhere, as the association to the names would be lost. ArraySort can swap the pointers to the "sort key" Boys, too - and thus the results can be displayed nicely, as shown below.

Quoteinclude \masm32\MasmBasic\MasmBasic.inc   ; Press F6 to assemble & link
.data
Times100
   REAL4 12.3, 12.1, 14.3, 14.5, 15.7, 16.3, 16.3, 23.5, 22.4, 12.4
Boys   dd Boy1, Boy2, Boy3, Boy4, Boy5, Boy6, Boy7, Boy8, Boy9, Boy10
Boy1   db "Alan", 0
Boy2   db "Bob", 0
Boy3   db "Chris", 0
Boy4   db "Dave", 0
Boy5   db "Edgar", 0
Boy6   db "Frank", 0
Boy7   db "Geoffrey", 0
Boy8   db "Hutch", 0
Boy9   db "Ian", 0
Boy10   db "John", 0
   
Init
   ; sort the results of a sprint
   mov esi, offset Times100
   Elements=sizeof Times100/4
   ArraySort esi
:Elements, offset Boys      ; sort esi, and adjust the Boys array accordingly
   PrintLine "Results of the last 100 m sprint"
   PrintLine "Rank", Tb$, "Time", Tb$, Tb$, "Name"
   For_ ebx=0 To Elements-1
      PrintLine Str$(ebx+1), Tb$, Str$("%3f secs \t", MemR4(esi, ebx)), Boys[4*ebx]   ; MemR4 allows
Str$(Real4 ptr [esi+4*ebx])
   Next
   Inkey CrLf$, "-- press any key --"
   
Exit
end start

Results of the last 100 m sprint
Rank    Time            Name
1       12.1 secs       Bob
2       12.3 secs       Alan
3       12.4 secs       John
4       14.3 secs       Chris
5       14.5 secs       Dave
6       15.7 secs       Edgar
7       16.3 secs       Frank
8       16.3 secs       Geoffrey
9       22.4 secs       Ian
10      23.5 secs       Hutch *)


*) I swear I didn't plan to put him on the last rank. It must be a bug in ArraySort :bg

Excerpt from the manual:

QuoteMbArraySort
            m2m ebx, 1000               ; we want 1000+1 elements (arrays are zero-based, 0...1000=1001)
            Dim MyR4(ebx) As REAL4
            Dim MyDW(ebx) As DWORD
            Dim KeyArr(ebx) As DWORD
            .Repeat
               Rand(-888.888, 999.999)         ; fill the Real4 array with random numbers between -888 and +999
               fstp MyR4(ebx)
               mov MyDW(ebx), Rand(1000)      ; same for the dword array, numbers between 0 and 1000
               mov KeyArr(ebx), ebx         ; we may need to know the original position before sorting
               dec ebx
            .Until Sign?
            lea edi, MyDW(0)               ; get the start address of the dword array
            ; ArraySort edi                  ; illegal - arrays are not zero terminated, so we must know the count
            ArraySort edi:Elements         ; edi is pointer to a dword array; Elements is # of dwords
            lea edi, MyR4(0)               ; get the start address of the Real4 array
            ArraySort REAL4 ptr edi:Elements   ; same but with single floats array (and we must declare them)
            ArraySort MyR4()               ; sort a MasmBasic Real4 array ascending
            ArraySort MyR4(+)            ; same, the + is optional
            ArraySort MyR4(+:123)         ; same but first 123 elements only
            
mov ecx, 123
            ArraySort MyR4(+:ecx)         ; same but using a register (or any other dword variable)
            ArraySort MyR4(-)               ; sort a MasmBasic Real4 array descending
            ArraySort MyR4(-:123)         ; same but first 123 elements only
            lea esi, KeyArr(0)               ; load start address of an array containing keys (e.g. original position)
            ArraySort MyR4(-), esi         ; sort Real4 array descending, keep key values with Real4 values
            ArraySort MyR4(+), KeyArr(), fill      ; use key array directly, fill with original order (0, 1, 2, ... n) before sorting

Rem   - no return value (all regs unchanged)
   - use for DWORD and REAL4 arrays; for strings, see QSort
   
- uses a very fast CombSort variant, may be faster than QuickSort for low elements counts (<10,000)
   - Real4 and Dword use the same algo; the only difference is that the Real4 variant applies an extra
     pass to invert the order of negative elements. Speedwise there is no measurable difference
[/b]

dedndave

i put a girls name in there, and it froze up   :red
maybe i should pick a name that doesn't start with "Z" ?

jj2007

Quote from: dedndave on April 06, 2011, 02:06:17 AM
i put a girls name in there, and it froze up   :red
maybe i should pick a name that doesn't start with "Z" ?

Give Z a kiss, and post the code that freezes, if any :naughty:

dedndave

you know i was pulling your leg, my friend   :P

jj2007

See here for a MasmBasic example with tooltips that show off when the user has CapsLock set and tries to type something in the edit control. You need to replace VK_SHIFT with VK_CAPITAL in the source.

jj2007

Following an exchange of views in the UniEdit thread, I updated RichMasm.exe (included in the MasmBasic package attached to the first post of this thread). Now Unicode RC files that for whatever reason lack the byte order mark (BOM) are still recognised as Unicode and saved accordingly.

Note that this is a pretty superfluous feature because with RichMasm, the contents of the resource files can simply be added to the bottom of the *.asc source, under "end start":

Quote...
end start

Rsrc
STRINGTABLE
BEGIN
   401,   "Введите текст  здесь"   ; "Enter text here" in Russian
   402,   "Нажмите на эту кнопку"   ; "Click on this button" in Russian
   403,   "Добро пожаловать"   ; "Welcome" in Russian
END
Rsrc

Pressing F6 (=assemble, link and run) triggers also the export of the text between the two Rsrc markers to a Unicode *.rc file. To use this feature with "real" Unicode, you need MasmBasic's wRes$() macro, e.g. as wSetWin$ hEdit=wRes$(401).

jj2007

Minor update, see top of thread. The editor (RichMasm.exe) barks now if it was not started from its native location, i.e. \masm32\RichMasm\RichMasm.exe

Remember to extract to the root of your Masm32 drive using folder names. This adds two folders to your Masm32 installation: \masm32\MasmBasic and \masm32\RichMasm. You can move the RichMasm folder (including all its sub-folders) into the MasmBasic folder, but not the other way round (but it's not very sensible to do that since updates extract to \masm32\RichMasm).

The May 2 update also solved a problem with Input$ when used directly e.g. for MovVal. This snippet works now:
Quoteinclude \masm32\MasmBasic\MasmBasic.inc   ; Download
.data?
Num1   REAL8 ?

   Init
   MovVal Num1, Input$("Type a number and hit Enter:  ")
   Inkey Str$("Your numbers is %f", Num1)
   Exit
end start