flat assembler
Message board for the users of flat assembler.

Index > Main > [fasmg] Issues when creating new CALM instruction

Author
Thread Post new topic Reply to topic
Calanor



Joined: 19 Jul 2015
Posts: 40
Location: Sweden
Calanor
After another break (my self-discipline leaves much to be desired), I've decided to continue with my coding project. I wanted to try to implement a "conditional CALM instruction" in a similar vein to match, check and the like, i.e. my new instruction would be followed by a jyes/jno check just like the others. After deciding that "macro calminstruction?..." wasn't quite what I wanted, I started to code one of the very few "calminstruction calminstruction?..."-instructions (for lack of a better term) I've ever written. I ran into some problems with such blocks before, but I now realise that I might have misunderstood how scope works in such situations.

The result so far works, but there are a couple of things that I am not entirely pleased with. First, I am using a "temporary symbol" to solve issues regarding scope. Also, when I do this I use asmcmd to basically run CALM instructions at the "parent's" level. I assume that this will cause whatever CALM instruction that's calling the conditional to be recompiled every time it's used?

Is there a better way to do this? I tried to find a solution using all manners of CALM instructions, but to no avail. The conditional in question checks whether or not the passed argument is any of the standard CPU-registers.

The @TMP symbol has to be initialised with a dummy value, unless "isreg" is actually used somewhere (which I assume it will be, it's kind of why I am coding it).

Code:
@TMP equ 0

calminstruction calminstruction?.isreg? arg*
        local tmp, i
        asmcmd =arrange =@TMP, arg
        match a?[b], @TMP
        jno _checkregs
                ; Memory location
                jump _exit
_checkregs:
        compute i, 0
_regloop:
                compute i, i + 1
                check i > elementsof @TMP
                jyes _exit
                        compute tmp, i metadataof @TMP
                        check tmp relativeto x86.r64 | tmp relativeto x86.r32 | tmp relativeto x86.r16 | tmp relativeto x86.r8
                        jno _regloop
                                asmcmd =check 1
                                exit
                jump _regloop
_exit:
        asmcmd =check 0
end calminstruction

calminstruction testing? somearg*
        isreg somearg
        jyes _yep
                asmcmd =display "No", 13
                exit
_yep:
                asmcmd =display "Yes", 13
end calminstruction    
Post 24 Aug 2022, 20:48
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8028
Location: Kraków, Poland
Tomasz Grysztar
The testing logic doesn't seem to be in the right place - by defining "isreg" this way you get it executed at the time when "testing" instruction is defined.
When you produce a line from inside such instruction, this line becomes part of the body of a compiled instruction (in this case, of the body of "testing"). You produce a line "arrange @TMP, somarg", and this line is then compiled as a part of "testing" instruction body, followed by "check 0" or "check 1". But all the other logic, including MATCH, is executed during the compilation of "testing", and therefore only once.

It might have looked like it worked, but you only check the value of a global @TMP once - at the time when "testing" is defined and "isreg" is called. Every time the "testing" is used, it re-defines @TMP by executing the "arrange" command in its compiled body, but this no longer has any effect on the result of the check (because the "check 0" or "check 1" is also already compiled).

I assume your intention was to execute the logic of "isreg" every time "testing" is executed - to do that, you should use CALL:
Code:
@TMP = 0

calminstruction @isreg arg*
        local tmp, i
        match a?[b], arg
        jno _checkregs
                ; Memory location
                jump _exit
_checkregs:
        compute i, 0
_regloop:
                compute i, i + 1
                check i > elementsof arg
                jyes _exit
                        compute tmp, i metadataof arg
                        check tmp relativeto x86.r64 | tmp relativeto x86.r32 | tmp relativeto x86.r16 | tmp relativeto x86.r8
                        jno _regloop
                                compute @TMP, 1
                                exit
                jump _regloop
_exit:
        compute @TMP, 0
end calminstruction

calminstruction testing? somearg*
        call @isreg, somearg
        check @TMP
        jyes _yep
                asmcmd =display "No", 13
                exit
_yep:
                asmcmd =display "Yes", 13
end calminstruction    
This doesn't look exactly like you wanted, especially since it requires additional CHECK of the stored result. But this is now a good moment to introduce a "macro calminstruction?." wrapper:
Code:
macro calminstruction?.isreg? var*
        call @isreg, var
        check @TMP
end macro

calminstruction testing? somearg*
        isreg somearg
        jyes _yep
                asmcmd =display "No", 13
                exit
_yep:
                asmcmd =display "Yes", 13
end calminstruction    
There's no real need to rewrite it as "calminstruction calminstruction?.", but you could clean it up further by using some kind of encapsulated symbol instead of global @TMP.
Post 24 Aug 2022, 21:34
View user's profile Send private message Visit poster's website Reply with quote
Calanor



Joined: 19 Jul 2015
Posts: 40
Location: Sweden
Calanor
Yes, when I played around with the code a bit after posting this, I realised that I get different results depending on from where in the code I'm calling "testing". Embarassed

It seems like there are some gaps in my understanding of how fasmg is handling things like this, so I am really grateful for your explanations. I'm not sure what you mean by "encapsulated symbol" though? A local of some sort?
Post 24 Aug 2022, 21:59
View user's profile Send private message Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 3489
Location: vpcmipstrm
bitRAKE
This is the technique I've used in the past, there might be a better way.
(As I'm still trying to get comfortable with the semantics.)
Code:
include 'cpu\x64.inc'
include 'xcalm.inc'

calminstruction @isreg arg*,@TMP*
        local tmp, i
        match a?[b], arg
        jno _checkregs
                ; Memory location
                jump _exit
_checkregs:
        compute i, 0
_regloop:
                compute i, i + 1
                check i > elementsof arg
                jyes _exit
                        compute tmp, i metadataof arg
                        check tmp relativeto x86.r64 | tmp relativeto x86.r32 | tmp relativeto x86.r16 | tmp relativeto x86.r8
                        jno _regloop
                                compute tmp, 1
                                publish @TMP, tmp
                                exit
_exit:
        compute tmp, 0
        publish @TMP, tmp
end calminstruction


macro calminstruction?.isreg? var*
        local TMP0,TMP1
        initsym TMP1,TMP0
        call @isreg, var, TMP1
        check TMP0
end macro

calminstruction testing? somearg*
        isreg somearg
        jyes _yep
                asm display 10,9,"No"
                exit
_yep:
                asm display 10,9,"Yes"
end calminstruction

_Label:
        testing rax
        testing dword [rax]
        testing _Label    

_________________
¯\(°_o)/¯ unlicense.org
Post 24 Aug 2022, 23:12
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8028
Location: Kraków, Poland
Tomasz Grysztar
You can make it access the hidden variable directly, to avoid having to evaluate symbolic link at run-time:
Code:
define @TMP

calminstruction @isreg arg*
        local tmp, i, result
        initsym @TMP, result
        match a?[b], arg
        jno _checkregs
                ; Memory location
                jump _exit
_checkregs:
        compute i, 0
_regloop:
                compute i, i + 1
                check i > elementsof arg
                jyes _exit
                        compute tmp, i metadataof arg
                        check tmp relativeto x86.r64 | tmp relativeto x86.r32 | tmp relativeto x86.r16 | tmp relativeto x86.r8
                        jno _regloop
                                compute result, 1
                                exit
                jump _regloop
_exit:
        compute result, 0
end calminstruction

match result, @TMP

        macro calminstruction?.isreg? var*
                call @isreg, var
                check result
        end macro

end match    
This uses a global variable to pass the link, but the link then becomes compiled and the global variable is no longer needed. And it could itself be a local variable, if everything was embedded in a macro, etc.
Post 25 Aug 2022, 08:21
View user's profile Send private message Visit poster's website Reply with quote
Calanor



Joined: 19 Jul 2015
Posts: 40
Location: Sweden
Calanor
Thanks for the suggestions, guys! Smile
Post 25 Aug 2022, 19:01
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2020, Tomasz Grysztar. Also on GitHub, YouTube, Twitter.

Website powered by rwasa.