flat assembler
Message board for the users of flat assembler.
![]() Goto page Previous 1, 2 |
Author |
|
Furs 11 Nov 2018, 11:06
revolution wrote: Or just use FCHS and then any implementation details about storage and number formats can be handled by the hardware. Then of course you have to use and instead, with 0x7F, but yeah. |
|||
![]() |
|
fasmnewbie 11 Nov 2018, 11:33
Furs wrote: I mean MSB = most significant byte. In your case it should be "most significant DWORD". When people refer to MSB, people talk about byte position, NOT a byte quantity. In any operand size larger than a byte, there always exists 2 important properties of that operand: its LSB and MSB. MSB always assumes the highest byte position of any given operand. This is pretty basic. I don't think you understand how floating format is laid out in memory or in a GPR. I also doubt your understanding on how addressing modes work. Here's the real layout of how floating point is parsed in memory; Code: x dq -45.345 mov al,byte[x+7] ;this approaches the MSB if you want to extract the highest byte and al,0x7f ;flip it mov byte[x+7],al ;copy it back to MSB or, btr dword[x+4],31 ;flips the bit 31 of the upper half of the REAL8. While XOR and AND also work, sometimes it is better being more explicit of what you instruction trying to do. For example in this case, BTR stands for Bit Test and Reset. It's much more clearer and descriptive. If you have access to my BASELIB routines, you get to see what you're talking about on-the-fly. You don't need "geometry" of some sort to see how a REAL8 data are parsed into memory. Code: ;This is "sbase32w.asm" format PE console include 'win32axp.inc' entry main section '.data' data readable writeable x dq -45.345 section '.text' code readable executable main: push x call fpdinfo call prnline btr dword[x+4],31 ;reset bit 31 of the upper portion of x push x call fpdinfo call prnline push x call prndbl call prnline push x push 64 call memview call halt call exitx With this output Code: C046AC28F5C28F5C 1.10000000100.01101010110000101000-11110101110000101000111101011100 Sign: 1 Exp : +5 Mant: 1.41703125 4046AC28F5C28F5C 0.10000000100.01101010110000101000-11110101110000101000111101011100 Sign: 0 Exp : +5 Mant: 1.41703125 45.345 00401000| 5C 8F C2 F5 28 AC 46 40 |+7|+7 00401008| 00 00 00 00 00 00 00 00 |+F|+15 00401010| 00 00 00 00 00 00 00 00 |+17|+23 00401018| 00 00 00 00 00 00 00 00 |+1F|+31 00401020| 00 00 00 00 00 00 00 00 |+27|+39 00401028| 00 00 00 00 00 00 00 00 |+2F|+47 00401030| 00 00 00 00 00 00 00 00 |+37|+55 00401038| 00 00 00 00 00 00 00 00 |+3F|+63 See how the value changes in memory via memview output using the correct addressing mode. |
|||
![]() |
|
fasmnewbie 11 Nov 2018, 11:44
revolution wrote: Or just use FCHS and then any implementation details about storage and number formats can be handled by the hardware. FCHS involves branching. While it sounds convenient it's probably not the best option here. |
|||
![]() |
|
fasmnewbie 11 Nov 2018, 12:09
Furs wrote:
Don't let yourself down ![]() XOR does work if you pit it against the entire DWORD. It just doesnt work against the MSB that way. Here's another example, showcasing the AND and XOR to flip the sign bit of a REAL8. Still using "sbase32w.asm" source; Code: x dq -0.02345 ;and dword[x+4],0x7fffffff xor dword[x+4],0x80000000 push x call prndbl ;Sign bit is reset, using either one of the above |
|||
![]() |
|
revolution 11 Nov 2018, 12:18
fasmnewbie wrote: FCHS involves branching. While it sounds convenient it's probably not the best option here. |
|||
![]() |
|
Furs 11 Nov 2018, 15:40
fasmnewbie wrote: When people refer to MSB, people talk about byte position, NOT a byte quantity. In any operand size larger than a byte, there always exists 2 important properties of that operand: its LSB and MSB. MSB always assumes the highest byte position of any given operand. This is pretty basic. You are truncating it to a 4-byte alignment (dword), but in fact: Code: btr dword[x+7],31 There's no reason to truncate a byte's position based on what you are accessing with, because x86 doesn't require aligned memory access (except for rare cases). So saying "MSB" in this context is very confusing, IMO. Should be "most significant DWORD" as I said. ![]() EDIT: BTW I am aware that it SHOULD be x+4, I'm not disagreeing with you. Just saying that you used the "your base's MSB" as the address which is confusing cause it means [x+7] in this case, which is wrong. i.e. just a matter of what you said, not what you meant ![]() Last edited by Furs on 11 Nov 2018, 18:42; edited 2 times in total |
|||
![]() |
|
revolution 11 Nov 2018, 15:44
Furs wrote: But why +4 and not +7? The position of the MSB byte is x+7. Literally. Doesn't matter the access mode. |
|||
![]() |
|
UniverseIsASimulation 11 Nov 2018, 16:12
It seems like there are more than one bug in the web-app. If I enter the arithmetic expression:
Code: pow(abs(x),y)*((x<0&mod(y,2)=1)*(-1)+(x>0|mod(y,2)=0)*1+((x<0¬(mod(y,1)=0)&(0/0)))) Transpiled into JavaScript and then executed (which is what the "Interpret" button does), it behaves like the "pow" function for all inputs. However, the compiler output is this: Code: finit fld dword [y] mov [result],2f fld dword [result] fxch fprem fxch fstp dword [result] mov [result],1f fld dword [result] fcomip st1 fstp dword [result] jne l640924 fld1 jmp l564953 l640924: fldz l564953: fld dword [x] mov [result],0f fld dword [result] fcomip st1 fstp dword [result] jna l337650 fld1 jmp l814480 l337650: fldz l814480: fxch fistp dword [result] mov eax,[result] fistp dword [result] and [result],eax fild dword [result] mov [result],0f fld dword [result] mov [result],1f fld dword [result] fsubp st1,st0 fmulp st1,st0 fld dword [y] mov [result],2f fld dword [result] fxch fprem fxch fstp dword [result] mov [result],0f fld dword [result] fcomip st1 fstp dword [result] jne l730422 fld1 jmp l471695 l730422: fldz l471695: fld dword [x] mov [result],0f fld dword [result] fcomip st1 fstp dword [result] jnb l46226 fld1 jmp l580080 l46226: fldz l580080: fxch fistp dword [result] mov eax,[result] fistp dword [result] or [result],eax fild dword [result] mov [result],1f fld dword [result] fmulp st1,st0 faddp st1,st0 fld dword [y] mov [result],1f fld dword [result] fxch fprem fxch fstp dword [result] mov [result],0f fld dword [result] fcomip st1 fstp dword [result] jne l920163 fld1 jmp l751054 l920163: fldz l751054: fld1 fxch fsubp st1,st0 fld dword [x] mov [result],0f fld dword [result] fcomip st1 fstp dword [result] jna l399314 fld1 jmp l871526 l399314: fldz l871526: fxch fistp dword [result] mov eax,[result] fistp dword [result] and [result],eax fild dword [result] mov [result],0f fld dword [result] mov [result],0f fld dword [result] fdivp st1,st0 fistp dword [result] mov eax,[result] fistp dword [result] and [result],eax fild dword [result] faddp st1,st0 fld dword [x] fabs fld dword [y] fxch fld1 fxch fyl2x fldl2e fdivp st1,st0 fmulp st1,st0 fldl2e fmulp st1,st0 fld1 fscale fxch fld1 fxch fprem f2xm1 faddp st1,st0 fmulp st1,st0 fxch fmulp st1,st0 fstp dword [result] That, if compiled with FASM and run, doesn't give the correct results. Any idea what's going on? |
|||
![]() |
|
Furs 11 Nov 2018, 18:27
revolution wrote:
He said [your base's MSB] to use in place of dword [x+4] which is confusing since x+4 is not the MSB. |
|||
![]() |
|
revolution 11 Nov 2018, 18:31
So x+4 is the MSD?
Anyhow, just use FCHS or FABS, they'll get the job done without this kind of confusion. |
|||
![]() |
|
fasmnewbie 12 Nov 2018, 11:19
Quote: EDIT: BTW I am aware that it SHOULD be x+4, I'm not disagreeing with you. Just saying that you used the "your base's MSB" as the address which is confusing cause it means [x+7] in this case, which is wrong. i.e. just a matter of what you said, not what you meant Razz Yeah, I can see where your confusion came from. It's about trying to match the idea of a "byte quantity" to a "dword" memory operand. I understand that problem. I was once there when I was completely as clueless to separate the idea of addressing modes from operand sizes. Thank god for the AMD manuals! ![]() |
|||
![]() |
|
fasmnewbie 12 Nov 2018, 11:28
universe
your code is too long for us to even begin with. Give a smaller test case so we can at least enjoy it in smaller pieces. Perhaps start with label names? |
|||
![]() |
|
fasmnewbie 12 Nov 2018, 11:49
Universe, here, I embedded the output above into the "sbase32w.asm" source file. You can run the program as it is and get to use the FPU-specific routines in there. For example, I inserted multiple calls to "fpu_stack" at certain jump points to confirm the transitions from 1 "label" to another. In the end I call "prnflt" routine to print the final result. I didn't make any modifications to the above output.
You can also insert calls to "fpu_stack" at suspected faulty lines to see the content of the FPU any time. For x = 5.4, y=3.4 the final answer is 309.1284. Is this expected? P/s Attachment will be deleted soon, because my quota doesn't look good, I think. Last edited by fasmnewbie on 13 Nov 2018, 14:27; edited 1 time in total |
|||
![]() |
|
UniverseIsASimulation 12 Nov 2018, 16:07
Yes, but for x=-2 and y=1.5, it returns 0. I expected it to return NaN.
|
|||
![]() |
|
fasmnewbie 12 Nov 2018, 18:12
Universe, it shouldn't return NaN because you already set it to FABS. Returning 0.0 is expected. It is now come down to your own set of rules against user input, at least for POW function taking negative base. I don't see anything wrong there.
For my own fpow function, I immediately set it to #err for negative base because I knew something confusing like this could happen. |
|||
![]() |
|
UniverseIsASimulation 05 Jan 2019, 17:48
Anyway, I've improved my compiler using the Duktape framework to be able not only to translate single directives from my own programming language into Assembly, but to also be able to translate entire simple programs stored in files. Here is one of the first programs I've written in the first programming language I've made myself:
Code: ;Advanced example: implementing the permutation algorithm. AsmStart debug=0 macro pushIntToStack x { sub esp,4 fld dword [x] fistp dword [esp] } macro pushPointerToStack x { sub esp,4 lea ebx,[x] mov [esp],ebx } macro pushStringToStack x { sub esp,4 mov dword [esp],x } format PE console entry start include 'win32a.inc' section '.text' code executable start: jmp enterNumber$ enterNumber db "Enter a whole number (1 - 1'000'000).",10,0 enterNumber$: pushStringToStack enterNumber call [printf] pushPointerToStack original jmp floatSign$ floatSign db "%f",0 floatSign$: pushStringToStack floatSign call [scanf] jmp permutationString$ permutationString db "The permutations of its digits are:",10,0 permutationString$: pushStringToStack permutationString call [printf] AsmEnd numberOfDigits:=0 i:=0 While i<10 countDigits[i]:=0 i:=i+1 EndWhile While original>0 numberOfDigits:= numberOfDigits + 1 lastDigit:= mod( original , 10 ) countDigits[ lastDigit ]:=countDigits( lastDigit ) + 1 original:= (original - lastDigit) / 10 EndWhile AsmStart if debug=1 AsmEnd i:=0 While i<10 subscript:=4*i AsmStart fld dword [subscript] fistp dword [subscript] mov ebx,[subscript] pushIntToStack (countDigits+ebx) pushStringToStack integerSign call [printf] AsmEnd i:=i+1 EndWhile AsmStart pushStringToStack newLineString call [printf] AsmEnd AsmStart end if AsmEnd topOfMyStack:=1 myStack[(numberOfDigits+1)]:=0 While topOfMyStack>0 currentNumberOfDigits:=myStack ( topOfMyStack * ( numberOfDigits + 1 ) ) i:=0 While i<currentNumberOfDigits currentNumber(i):=myStack ( topOfMyStack * ( numberOfDigits + 1 ) + ( i + 1 ) ) i:=i+1 EndWhile AsmStart if debug=1 AsmEnd i:=0 While i<currentNumberOfDigits subscript:=i*4 AsmStart fld dword [subscript] fistp dword [subscript] mov ebx,[subscript] pushIntToStack (currentNumber+ebx) pushStringToStack integerSign call [printf] AsmEnd i:=i+1 EndWhile AsmStart pushStringToStack newLineString call [printf] AsmEnd AsmStart end if AsmEnd topOfMyStack:=topOfMyStack-1 If currentNumberOfDigits=numberOfDigits i:=0 While i<numberOfDigits subscript:=i*4 AsmStart fld dword [subscript] fistp dword [subscript] mov ebx,[subscript] pushIntToStack (currentNumber+ebx) pushStringToStack integerSign call [printf] AsmEnd i:=i+1 EndWhile AsmStart pushStringToStack newLineString call [printf] AsmEnd Else i:=0 While i<10 counter:=0 j:=0 While j<currentNumberOfDigits If currentNumber(j)=i counter:=counter+1 EndIf j:=j+1 EndWhile If counter<countDigits(i) topOfMyStack:=topOfMyStack+1 myStack(topOfMyStack*(numberOfDigits+1)):=currentNumberOfDigits+1 j:=0 While j<currentNumberOfDigits myStack(topOfMyStack*(numberOfDigits+1)+(j+1)):=currentNumber(j) j:=j+1 EndWhile myStack (topOfMyStack * (numberOfDigits + 1) + (j + 1) ) := i EndIf i:=i+1 EndWhile EndIf EndWhile AsmStart invoke system,_pause invoke exit,0 _pause db "PAUSE",0 integerSign db "%d",0 newLineString db 10,0 section '.rdata' readable writable original dd ? result dd ? lastDigit dd ? numberOfDigits dd ? countDigits dd 11 dup(?) subscript dd ? myStack dd 1000 dup(?) topOfMyStack dd ? counter dd ? i dd ? currentNumber dd 11 dup(?) currentNumberOfDigits dd ? j dd ? section '.idata' data readable import library msvcrt,'msvcrt.dll' import msvcrt,printf,'printf',system,'system',exit,'exit',scanf,'scanf' AsmEnd The source code of the compiler, as well as the instructions on how to compile it and use it, can be downloaded here. So, what do you think about it? Is it worth continuing developing it? I am also dreaming about making my own LISP-like language, in which you will able to use both S-expressions and infix-expressions (since S-expressions come handy in array and string-manipulation, and infix-expressions come handy in arithmetic expressions), but I am unlikely to have time to develop it in foreseeable future. |
|||
![]() |
|
Q9000 16 Nov 2020, 15:09
The actual website is down since a year or so but archive.org had at least picked the website up: https://web.archive.org/web/20191228041254/http://flatassembler.000webhostapp.com/compiler.html
It didn't save the actual program (.exe). |
|||
![]() |
|
Goto page Previous 1, 2 < Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.