flat assembler
Message board for the users of flat assembler.

Index > Compiler Internals > Understanding internal handling of ORG directive

Author
Thread Post new topic Reply to topic
shutdownall



Joined: 02 Apr 2010
Posts: 517
Location: Munich
shutdownall 09 May 2012, 23:49
I want to implement a new feature in a special version of FASM.
I want to have codeblocks defined somewhere in source which could be moved around later in output file. It's for using FASM for retro computing, allowing mixing of BASIC and ASSEMBLER instructions for Sinclairs ZX81 models. If you don't know don't care about it. Wink

One mainly used solution of combining BASIC and ASSEMBLER is to put an assembler codeblock in a REM line, which is ignored by interpreting BASIC but could be executed from BASIC later. Simple example:

Code:
   ORG <start address of basic>
 1 REM COPYRIGHT NOTICE
LABEL:
10 REM <some assembler codeblock needed here>
20 DIM P$(22,32)
30 CLS
40 FOR Y=1 TO 22
50 PRINT P$(Y);
60 NEXT Y
100 REM MAIN LOOP
110 INPUT C$
120 IF C$="SAVE" THEN GOTO 500
130 IF C$="QUIT" THEN GOTO 9000
140 IF LEN C$ <>5 THEN GOTO 110
...
9000 END

LABEL2:

codeblock at LABEL
; assembler instructions
  PUSH HL
  LD BC,$FE77
  LD A,0
  OUT (C),A
...
end codeblock

LABEL3:
<some other data needed, display buffer, etc.>

    


So I want to assemble the codeblock at another ORG (LABEL) and want to switch after end of this codeblock to the previous value of ORG.
Lets say, LABEL3==LABEL2.

So I tried to use org_directive in assemble.inc of FASM implicitely in my instruction codeblock (which has syntax like virtual). The code of org_directive is following:

Code:
org_directive:
    lods    byte [esi]
  cmp     al,'('
        jne     invalid_argument
    cmp     byte [esi],'.'
    je      invalid_value
       call    get_qword_value
     mov     cl,[value_type]
     test    cl,1
        jnz     invalid_use_of_symbol
       mov     [labels_type],cl
    mov     ecx,edi
     sub     ecx,eax
     adc     edx,0
       neg     edx
 mov     dword [org_origin],ecx
      mov     dword [org_origin+4],edx
    mov     [org_registers],0
   mov     [org_start],edi
     mov     edx,[symbol_identifier]
     mov     [org_symbol],edx
    cmp     [output_format],1
   ja      instruction_assembled
       cmp     edi,[code_start]
    jne     instruction_assembled
       cmp     eax,100h
    jne     instruction_assembled
       bts     [format_flags],0
    jmp     instruction_assembled
    


I save the value of org_origin at start of my codeblock and write it back at end of my codeblock and have following behaviour:

LABEL3 is not same as LABEL2 (as expected) but has previous value plus size of codeblock.
So LABEL3 = LABEL2 + sizeof <codeblock>

One example with values:
LABEL1=4000h
LABEL2=4500h
LABEL3=4550h
codeblock start at 4000h and ends at 4050h
So the switch back at the end works in principle (4050h to 4500h) but not exactly (4550h).

So I am wondering when and how the corresponding address values are calculated or resolved and how is the best way to influence it in the way I like to use. So how can I restore the old org value ??? I tried to restore org_start but then I override my codeblock with the code following codeblock. So that makes no sense.

By the way, I have to copy this codeblock later at right position but like this kind and order of definition as it is very good readable in the listing of the whole application. Thats the way why I don't like to use macro, the other is that the macro has to be defined first. So I want to give some free handling to software developers to build the code in an easily human readable form and process all necessary stuff in the background.

So thank you for any help regarding this problem. Very Happy
Post 09 May 2012, 23:49
View user's profile Send private message Send e-mail Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8351
Location: Kraków, Poland
Tomasz Grysztar 10 May 2012, 08:58
VIRTUAL directive does restore the original ORG value when the block ends, so you can look at its handler for an example. In principle you need to restore the complete set of variables: org_origin, org_origin_sign, org_registers, org_symbol, org_start in order to restore the ORG value.
Post 10 May 2012, 08:58
View user's profile Send private message Visit poster's website Reply with quote
shutdownall



Joined: 02 Apr 2010
Posts: 517
Location: Munich
shutdownall 10 May 2012, 10:41
Thanks for that hint, will take a look on it this evening. Wink
In the night I had the idea to implement a substract of the code size in the codeblock when restoring but now I try your advice with the org handling in virtual directive.
Post 10 May 2012, 10:41
View user's profile Send private message Send e-mail Reply with quote
shutdownall



Joined: 02 Apr 2010
Posts: 517
Location: Munich
shutdownall 10 May 2012, 10:47
By the way, I found out that during assembling process (assemble.inc) the org value of that label is not availble directly, only the (possible) storage address of the label I think, which is calculated later in formatting process.

That point makes it complicate to realize this function in assembling process but could be worked around with an additional substraction of the codesize after the label.

But will check it with virtual directive handling first. Very Happy
Post 10 May 2012, 10:47
View user's profile Send private message Send e-mail Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8351
Location: Kraków, Poland
Tomasz Grysztar 10 May 2012, 11:34
To define this precisely, some additional terminology is needed. When fasm generates instructions or data it stores them consecutively in a flat memory area, when instruction/directive handler is invoked, EDI register contains the address in that area which is the current "point of assembly", place where the next opcode or data is to be put. With ORG directive programmer specifies for a given "point of assembly" what run-time address should that position correspond to. So we have an assembly-time addresses, the "assembly points", which have to be translated to the run-time addresses. For example the "$" symbol always translates to the run-time address corresponding to the current assembly point.

Now for the internal variables. The "org_start" value is the assembly point of the beginning of current addressing space - this is important for the LOAD/STORE directives, as they are allowed to operate only within this area, which is between the "org_start" and the current assembly point (EDI).

The "org_origin" is the value of hypothetical assembly point that would correspond to the run-time address of 0. When some value is specified to ORG directive, the "org_origin" is computed by substracting EDI from that value. The reverse operation can then be used easily compute the run-time address corresponing to any assembly point. For example to compute the "$" value at any time, you need to substract "org_origin" from EDI.

In the latest versions of fasm the value of symbol can be larger that 64 bits, therefore there was additional variable "org_origin_sign" holding the higher bits of the "org_origin" value (as the values are currently 65-bit, it is simply sign bit, hence the name).

The "org_registers" and "org_symbol" are for the case when the run-time address is relative to registers and/or relocatable section or external symbol. They are therefore also an important part of the address origin storage.
Post 10 May 2012, 11:34
View user's profile Send private message Visit poster's website Reply with quote
shutdownall



Joined: 02 Apr 2010
Posts: 517
Location: Munich
shutdownall 10 May 2012, 11:58
Thank you for that excellent and full explanation.

I use the flat model and 16 bit only, so org_origin_sign is not in my 1.69 version (new feature) and not needed and don't use relocation (not now, dont know if ever useful in my 16 bit context). Shocked
Post 10 May 2012, 11:58
View user's profile Send private message Send e-mail Reply with quote
shutdownall



Joined: 02 Apr 2010
Posts: 517
Location: Munich
shutdownall 10 May 2012, 22:42
Tomasz Grysztar wrote:

The "org_origin" is the value of hypothetical assembly point that would correspond to the run-time address of 0. When some value is specified to ORG directive, the "org_origin" is computed by substracting EDI from that value. The reverse operation can then be used easily compute the run-time address corresponing to any assembly point. For example to compute the "$" value at any time, you need to substract "org_origin" from EDI.


This was very helpful for me. It did not help just to save all variables you named in your other posting. I am not sure, maybe has to do something with EDI. So now I did another way, I computed the actual realtime address like described above and at the end of the codeblock I use a call to org_directive again with that computed value. Works great. Thanks. Very Happy

Here is the code:

Code:
codeblock_directive:
       lodsb
       cmp     al,80h
      jne     invalid_operand      ; valid instruction only with address value (codeblock at ...)
 lodsb
       cmp     al,'('
        jne     invalid_operand      ; valid only with immediate or label (no register)
     cmp     byte [org_back],0
   jnz     missing_end_directive  ; check if another "open" codeblock
        dec     esi
 mov     eax,edi
     sub     eax,dword [org_origin]   ; compute realtime address (effective address)
     push    edi eax
     mov     edi,org_back               ; store org directive with actual effective address for use with "end codeblock"
       mov     al,'('
        stosb
       mov     al,2
        stosb
       pop     eax
 stosw
       mov     al,')'
        stosb
       mov     al,0Fh
      stosb
       pop     edi
 jmp     org_directive     ; do required org for this codeblock
end_codeblock:
        push    esi
 mov     esi,org_back
        call    org_directive     ; reset org to previous value
     pop     esi
 xor     eax,eax
     mov     byte [org_back],al  ; mark codeblock as "closed"
  ret
    



And here the result in the listing of some sample code:

Code:
                                        ;labelautodetect
                                        ;labelusenumeric
                                        format binary
                                        
                                                AUTOLINE 20
                                        
                                                ORG     16514
                                        
0000: [4082] 00 14 04 00 EA 33 33 76    VLAB1:  REM "NN"
                                        VLAB2:
                                        
0008: [408A] FF FF FF FF FF FF FF FF            db $80 dup($FF)
             FF FF FF FF FF FF FF FF    
             FF FF FF FF FF FF FF FF    
             FF FF FF FF FF FF FF FF    
             FF FF FF FF FF FF FF FF    
             FF FF FF FF FF FF FF FF    
             FF FF FF FF FF FF FF FF    
             FF FF FF FF FF FF FF FF    
             FF FF FF FF FF FF FF FF    
             FF FF FF FF FF FF FF FF    
             FF FF FF FF FF FF FF FF    
             FF FF FF FF FF FF FF FF    
             FF FF FF FF FF FF FF FF    
             FF FF FF FF FF FF FF FF    
             FF FF FF FF FF FF FF FF    
             FF FF FF FF FF FF FF FF    
                                        
                                        codeblock at VLAB2
                                        
0088: [408A] FF                                 db $FF
0089: [408B] C3 8A 40                           JP VLAB2
                                        
                                        end codeblock
                                        
008C: [410A] 99                                 db $99
                                        
                                        
                                        codeblock at VLAB1
                                        
008D: [4082] 00 00 00 00 00 00 00 00            db $10 dup(0)
             00 00 00 00 00 00 00 00    
                                        
                                        end codeblock
                                        
                                        
009D: [410B] 63 6F 6E 74 69 6E 75 65            db "continue here again"
             20 68 65 72 65 20 61 67    
             61 69 6E                   
    


I think now I can easily implement PHASE / DEPHASE instructions to switch org values as described in another post. Some assembler do support this.
Post 10 May 2012, 22:42
View user's profile Send private message Send e-mail 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-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.