Author Topic: Assembler 'org' directive.  (Read 5087 times)

0 Members and 1 Guest are viewing this topic.

Offline paulcaTopic starter

  • Super Contributor
  • ***
  • Posts: 6561
  • Country: gb
Assembler 'org' directive.
« on: June 08, 2025, 11:14:28 pm »
I expected this:
Code: [Select]
.org 0x0000
RET
.org 0x0002
RET

to produce this:
Code: [Select]
C9
00
C9

It doesn't.

It produces:
Code: [Select]
C9
C9

Can someone explain to me how this is useful to... ANYONE?

Any suggestions on making "ORG" have purpose when laying out memory, that doesn't require a block fill for each and every single one of them?
"What could possibly go wrong?"
Current Open Projects:  68000 Self Build computer + OS.
 

Offline Analog Kid

  • Super Contributor
  • ***
  • Posts: 5063
  • Country: us
  • DANDY fan (Discretes Are Not Dead Yet)
Re: Assembler 'org' directive.
« Reply #1 on: June 08, 2025, 11:33:07 pm »
What assembler?
Pretty sure MASM wouldn't do that. That's just wrong, even if 0 is a NOP.
 

Offline paulcaTopic starter

  • Super Contributor
  • ***
  • Posts: 6561
  • Country: gb
Re: Assembler 'org' directive.
« Reply #2 on: June 08, 2025, 11:41:07 pm »
What assembler?
Pretty sure MASM wouldn't do that. That's just wrong, even if 0 is a NOP.

It's both z80asm and sjasmplus.

Both of their manuals state that "ORG" will not allocate anything, nor produce anything in the output.

If I open the "list" file, the asm does know what I intend, but it doesn't output in the "bin" file that way.

eg:
Code: [Select]
0000      restart_0:
0000 c3 00 01       jp reboot
0003
0003      ; Later these can vector into ROM routines
0003      ; Or user RAM
0003          ORG 0x0008
0008      restart_1:
0008 c9         RET
0009
0009          ORG 0x0010
0010      restart_2:
0010 c9         RET
0011
0011          ORG 0x0018
0018      restart_3:
0018 c9         RET
0019          ORG 0x0020
0020      restart_4:
0020 c9         RET
0021          ORG 0x0028
0028      restart_5:
0028 c9         RET
0029          ORG 0x0030
0030      restart_6:
0030 c9         RET
0031          ORG 0x0038
0038      restart_7:
0038      ; General MODE 1 Interrupt     
0038      mode1_int_restart:
0038          ; Empty
0038
0038      ; NMI Interupt
0038          ORG 0x0066
0066      nmi_restart:
0066          ; Empty
0066
0066          ORG 0x0100
0100      reboot:

If it just filled in the gaps with 0 and did this in the ".bin" file I'd be golden.

What I get is this:
Code: [Select]
0000000 00c3 c901 c9c9 c9c9 31c9 fdff fe3e 47ed
  EDIT:  Apologies this is byte order flipped, but it's late.

Garbage.

Too many rabbit holes send me down the whole linker route and defining my own ABI.  I have no target platform.  I just want verbatim raw bytes per address.

The other option is to ...

Generate my "block" ROM structure in one ASM process.  Then use the file rewriting directives to "FPOS" code in.

I don't mind for large blocks, but for vectors and resets it might be better to manually nop; pad.

Surely this has to be easier, right?
« Last Edit: June 08, 2025, 11:50:43 pm by paulca »
"What could possibly go wrong?"
Current Open Projects:  68000 Self Build computer + OS.
 

Offline ejeffrey

  • Super Contributor
  • ***
  • Posts: 4852
  • Country: us
Re: Assembler 'org' directive.
« Reply #3 on: June 09, 2025, 12:04:35 am »
I haven't used those platforms for years but different assemblers and platforms work differently.  On some assemblers, especially those where the standard output file is a simple binary (like CP/M or DOS COM files), the org directive doesn't what you are asking.  Instead, org defines the address that the OS will load the binary into memory.  In that case the only thing it did is change how jump and load labels are interpreted.

On these systems you would only ever use a single .org directive.  Once we moved beyond a single source per program, linkers took care of that offset and org is used to position relative to the current section start.
 

Offline Analog Kid

  • Super Contributor
  • ***
  • Posts: 5063
  • Country: us
  • DANDY fan (Discretes Are Not Dead Yet)
Re: Assembler 'org' directive.
« Reply #4 on: June 09, 2025, 12:24:12 am »
Looks like those are demented assemblers.
Any other choices available to you?
 

Offline radiolistener

  • Super Contributor
  • ***
  • Posts: 5745
  • Country: Earth
Re: Assembler 'org' directive.
« Reply #5 on: June 09, 2025, 01:49:17 am »
I expected this:
Code: [Select]
.org 0x0000
RET
.org 0x0002
RET

to produce this:
Code: [Select]
C9
00
C9

This is incorrect. 0x00 is usually NOP, but there is no NOP in your code.

ORG don't produce code, it just setup a new instruction pointer.
This is what happens in your code:

Code: [Select]
.org 0x0000     ; the next instruction should be placed at 0x0000
RET             ; this instruction is placed at 0x0000
.org 0x0002     ; the next instruction should be placed at 0x0002
RET             ; this instruction is placed at 0x0002

there are just two ret's, so the compilation result will be:
0x0000: 0xc9
0x0002: 0xc9

so, the correct result is just two 0xc9, but their addresses are not sequential, first one is placed at 0x0000 and second one is placed at 0x0002.

If compiler fills 0x00 between 0xc9 - this is serious bug of the compiler.


If it just filled in the gaps with 0 and did this in the ".bin" file I'd be golden.

The BIN output format does not support multiple ORG directives. Technically, the compiler should reject such input and avoid generating a BIN file, however, some compilers may not report an error and instead produce a BIN file with undefined or incorrect content. In some implementations, filling the gaps with zeros in BIN for this case is not a bug but a documented behavior, since the BIN format lacks a mechanism to represent address gaps, unlike formats such as HEX.

If your code contains multiple ORG directives, then you need to use the HEX output format instead of BIN.
« Last Edit: June 09, 2025, 02:03:49 am by radiolistener »
 

Offline Analog Kid

  • Super Contributor
  • ***
  • Posts: 5063
  • Country: us
  • DANDY fan (Discretes Are Not Dead Yet)
Re: Assembler 'org' directive.
« Reply #6 on: June 09, 2025, 02:03:11 am »
Wellll, all I can say is that MASM does exactly the right thing here. From this code:

Code: [Select]
ORG 1000H
RET

ORG 1002H
RET

I get this executable code:



(this was a Windows console program)

Obviously it's got to fill the space in between with something, so zeroes are the obvious choice.
 

Offline radiolistener

  • Super Contributor
  • ***
  • Posts: 5745
  • Country: Earth
Re: Assembler 'org' directive.
« Reply #7 on: June 09, 2025, 02:10:38 am »
Wellll, all I can say is that MASM does exactly the right thing here. From this code:

I just wonder what it produces for this code:
Code: [Select]
ORG 0FFFFH
RET

ORG 8000H
RET

 :popcorn:
 

Offline Analog Kid

  • Super Contributor
  • ***
  • Posts: 5063
  • Country: us
  • DANDY fan (Discretes Are Not Dead Yet)
Re: Assembler 'org' directive.
« Reply #8 on: June 09, 2025, 02:14:05 am »
Wellll, all I can say is that MASM does exactly the right thing here. From this code:

I just wonder what it produces for this code:
Code: [Select]
ORG 0FFFFH
RET

ORG 8000H
RET

 :popcorn:

Sorry, I don't have the time to scroll through that much of a debug listing.
Life's too damn short for that.
 

Offline radiolistener

  • Super Contributor
  • ***
  • Posts: 5745
  • Country: Earth
Re: Assembler 'org' directive.
« Reply #9 on: June 09, 2025, 02:25:27 am »
Obviously it's got to fill the space in between with something, so zeroes are the obvious choice.

The compiler should not make assumptions or insert instructions that are not explicitly present in the source code. Using multiple ORG directives when generating binary output is considered undefined behavior. While some compilers may handle such cases in their own way (e.g., by padding with zeros), this behavior is implementation-defined and should not be relied upon. Other compilers may handle it differently or even report an error.

Actually this is not so much a compiler behavior as it is a limitation of the linker and binary output format. The BIN format lacks the ability to represent address gaps or discontinuous memory layouts as defined by multiple ORG directives, making it impossible to faithfully preserve the structure specified in the source code.
« Last Edit: June 09, 2025, 02:29:26 am by radiolistener »
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 6464
  • Country: nz
Re: Assembler 'org' directive.
« Reply #10 on: June 09, 2025, 02:35:12 am »
Obviously it's got to fill the space in between with something, so zeroes are the obvious choice.

No, the first part is not obvious.

Using a proper executable format such as IHEX or ELF the bytes that you specify (in your case two RET) will be written into RAM at the addresses you specify, and the rest of RAM will be left untouched.

BIN format doesn't know what address it should be loaded at, it's just raw bytes. You should get the same bytes regardless of that .ORG you use. Converting something with more than one block of data into BIN is completely entitled to simply concatenate the blocks together.
 

Offline radiolistener

  • Super Contributor
  • ***
  • Posts: 5745
  • Country: Earth
Re: Assembler 'org' directive.
« Reply #11 on: June 09, 2025, 02:40:32 am »
just tried your code with zasm with output to HEX:

test_org.asm:
Code: [Select]
    org     0x1000
    ret
   
    org     0x1002
    ret

test_org.hex:
Code: [Select]
:01000000C936
:01000200C934
:00000001FF

test_org.lst:
Code: [Select]
1000:              org     0x1000
1000: C9          ret
                 
                  org     0x1002
1002: C9          ret


; +++ segments +++

#CODE          = $1000 =  4096,  size = $0003 =     3

; +++ global symbols +++

_end    = $1003 =  4099          test_org.asm:1 (unused)
_size   = $0003 =     3          test_org.asm:1 (unused)
_z80_   = $0001 =     1          test_org.asm:1 (unused)


total time: 0.0006 sec.
no errors

As you can see there is no zero filling between ORG directives.
 

Offline paulcaTopic starter

  • Super Contributor
  • ***
  • Posts: 6561
  • Country: gb
Re: Assembler 'org' directive.
« Reply #12 on: June 09, 2025, 08:25:44 am »
It's a chicken and the egg problem.

The ASM I am trying to write is the over all memory map as defined from the ROM chip point of view.  It is that which defines, for example  "USER_BASE" where user_main goes.  user_main in my case is (currently at) 0x1000.  Right in the middle of ROM.

In particular, there are "hardcoded" addresses in the CPU protocol, such as reset vectors and interrupt vectors.  These have to go in the right place.

I did some more thinking.  My resistance to "self padding" with declarations is ... not valid.  I have no choice.  I need to lay out a full 0x8000 bytes into a HEX file and flash it to the ROM.

OR...  I don't use "Full chip erase" and I align my memory regions to the flash sectors, I write my stuff in blocks, then I map those blocks to chip sectors.  I write my programmer to take multiple files with a "Partition descriptor" and flash each into it's own memory location.

The advantage being, when I am in "user land" I only have one asm file with one ORG and I only need to erase and write on sector.  As my programmer is a slow DIY job I'm afraid to optimise, this is a good thing.

On 00 being "NOP".  To be honest this is a mistake and unless I see a reason not to, i intend to "pad" out with "HALT".  That or borrow from STM32 and fill it all with a "RESET vector call" (a single byte opcode) that results in an infinite loop.... where at least if you had a debugger you can get the stack trace of how it ended up there.  I put myself to sleep last night thinking about if it was a good idea to attempt to write the last few entries off the stack to the LCD screen.  However, usually when you end up in the "Hard Fault" handler there are reasons that might also be a bad idea.  ie.  It's very likely the code hit a point where state was corrupted and it couldn't continue.  As a programmer, it's like something I would do, is directly call the "hard_fault" handler as a way of raising a "RuntimeException" or a "IQuitSodThisForAGameOfDarts".

« Last Edit: June 09, 2025, 09:11:38 am by paulca »
"What could possibly go wrong?"
Current Open Projects:  68000 Self Build computer + OS.
 

Offline paulcaTopic starter

  • Super Contributor
  • ***
  • Posts: 6561
  • Country: gb
Re: Assembler 'org' directive.
« Reply #13 on: June 09, 2025, 09:05:24 am »
If I "Do nothing", regards padding and write the sparse object files "as is" just to the correct addresses in flash...

The padding will consist of 0xFF.

Interestingly this is:
        rst 38h           ff

A Mode 1 interrupt - Restart vector 7.

Not ideal, but could be worse.

EDIT:  I own that ROM vector.  I get to decide.  Needs investigating, but if I end up in the RST7 handler and the interrupt flags are NOT set, then I know someone sent us there.  If we make "that" process, of calling the CPU interrput handler directly ILLEGAL, then I can simply test the interrupt flags and if not set, jump to the hard_fault handler.  Getting to where I wanted to go, without having to 00 the flash every time.
« Last Edit: June 09, 2025, 09:14:53 am by paulca »
"What could possibly go wrong?"
Current Open Projects:  68000 Self Build computer + OS.
 

Offline paulcaTopic starter

  • Super Contributor
  • ***
  • Posts: 6561
  • Country: gb
Re: Assembler 'org' directive.
« Reply #14 on: June 09, 2025, 09:49:28 am »
On "what I expected" being incorrect.

It does make sense I was headed up the wrong tree.  I had a growing feeling saying, "you are trying to dig a screw out with a spade.... find the screwdriver instead." - in other words, what I was trying to do what not in the capabilities of the tools I was using.  Suggesting either what I was trying to do was wrong, or the tool was wrong.

The .org statement does nothing, but change the assembler state, regards the "base vector" of any labels.

The only place it will really be used in instructions is in the likes of:

LD A,(my_label)

In this case, "my_label" will be (last ORG address + instruction counter delta) of where "my_label" is actually anchored in the code.

Other than in directives that's about all it does.

If I want to split memory regions along those "ORG" definitions, I need to do that somehow/somewhere else.  Be that the full formal linker defs or in the ROM partitioning while making the "ASCI-HEX" file for the programmer.
« Last Edit: June 09, 2025, 09:51:03 am by paulca »
"What could possibly go wrong?"
Current Open Projects:  68000 Self Build computer + OS.
 

Offline bingo600

  • Super Contributor
  • ***
  • Posts: 2316
  • Country: dk
Re: Assembler 'org' directive.
« Reply #15 on: June 09, 2025, 10:17:21 am »
I just tried for fun to build from source

pasmo
https://pasmo.speccy.org/#down

z88dk
git clone --recursive https://github.com/z88dk/z88dk.git

Test Source (asm-tst.asm)
Code: [Select]
    org     0x1000
    ret
   
    org     0x1002
    ret


pasmo:
Code: [Select]
:~/tmp/z80-asm/pasmo/pasmo-0.5.5$ ./pasmo asm-tst.asm asm-tst.bin
:~/tmp/z80-asm/pasmo/pasmo-0.5.5$ od -x asm-tst.bin
0000000 00c9 00c9
0000003

pasmo:
Code: [Select]
./pasmo --hex asm-tst.asm asm-tst.hex

cat asm-tst.hex
:03100000C900C95B
:00000001FF


z88dk:
Code: [Select]
:~/tmp/z80-asm/z88dk/bin$ ./z88dk-z80asm -b asm-tst.asm
asm-tst.asm:4: error: ORG redefined
  ^---- org 0x1002
      ^---- org 4098

z88dk uses another method to do "multi placement"
https://github.com/z88dk/z88dk/issues/247

z88dk "regions" seems nice.


But if using simple "ORG" pasmo seems to do what you want

/Bingo
« Last Edit: June 09, 2025, 10:48:55 am by bingo600 »
 

Offline DiTBho

  • Super Contributor
  • ***
  • Posts: 5109
  • Country: gb
Re: Assembler 'org' directive.
« Reply #16 on: June 09, 2025, 10:17:57 am »
Org is different even in GNU as
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline paulcaTopic starter

  • Super Contributor
  • ***
  • Posts: 6561
  • Country: gb
Re: Assembler 'org' directive.
« Reply #17 on: June 09, 2025, 11:06:24 am »
Consider....   generate a bin file that contains nothing but

"JP (Whoooooopsie)"

object code.  A single 8 byte opcode like RSTn.

Then build my memory map over the top of that file.  So ALL uninitialised ROM jumps to "Whooopsie" handler.

... and if that RST happens to be RST7 it's opcode is.... 0xFF which is what the flash rom will initialise to anyway.

It just means, as I mentioned above, I need to make sure I can (abuse) use that default RST vector that way, as it is shared with Mode1 interrupt.
« Last Edit: June 09, 2025, 11:08:55 am by paulca »
"What could possibly go wrong?"
Current Open Projects:  68000 Self Build computer + OS.
 

Offline bingo600

  • Super Contributor
  • ***
  • Posts: 2316
  • Country: dk
Re: Assembler 'org' directive.
« Reply #18 on: June 09, 2025, 11:15:07 am »
Somewhat unrelated , but have you seen this PI-Pico based eprom emulator
https://www.mikrocontroller.net/topic/577231#new

http://mino-elektronik.de/Gemischtes/ROM-Simulator.html

I'm 99% sure mino is on this forum too.

 
The following users thanked this post: paulca

Offline paulcaTopic starter

  • Super Contributor
  • ***
  • Posts: 6561
  • Country: gb
Re: Assembler 'org' directive.
« Reply #19 on: June 09, 2025, 11:20:44 am »
This is my ROM simulator :)

I do however use an STM32 to take the ASM output and put it on a read flash rom chip via a ZIF socket.

Work, like started this thread does not pass the simulator test so I don't bother trying the hardware.

It's like unit testing though.  It only tests that the code behaves in the test harness.  The real world always has surprises.  So "integration" testing with partial or complete hardware systems has to happen eventually.



Code: [Select]
// ram_async.v
module ram_async #( parameter   init_file = "asm/rom.hex",
                    parameter   size      = 32768)
(   
    input wire [14:0]   addr,
    input wire          nCE,
    input wire          nOE,
    input wire          nWE,
    inout wire [7:0]    data,
    input wire          clk
);
   
    reg                 _nCE;
    reg                 _nOE;
    reg                 _nWE;
    reg     [7:0]       ram_data [0:size-1]; // 32k
    reg     [7:0]       io_buffer;
    reg     [14:0]      address_buffer;
    reg                 o_drive;

    initial begin
        io_buffer = 8'bz;
        o_drive = 0;
        _nCE = 1;
        _nOE = 1;
        _nWE = 1;
        $readmemh(init_file, ram_data);       

    end
   

    always @(posedge clk) begin
        _nCE <= nCE;
        _nOE <= nOE;   
        _nWE <= nWE;   
        address_buffer <= addr;
        if( ~_nWE ) begin
            io_buffer <= data;
        end
    end

    always @(posedge clk) begin
        if(~_nOE & ~_nCE ) begin
            io_buffer <= ram_data[address_buffer];
            o_drive <= 1;
        end  else begin
            o_drive <= 0;
        end
    end

    always @(negedge clk) begin
        if (~_nWE & ~_nCE) begin
            ram_data[address_buffer] <= io_buffer;
            o_drive <= 0;
        end
    end

   
    assign data = (o_drive) ? io_buffer : 8'bz;


endmodule

"What could possibly go wrong?"
Current Open Projects:  68000 Self Build computer + OS.
 

Offline bingo600

  • Super Contributor
  • ***
  • Posts: 2316
  • Country: dk
Re: Assembler 'org' directive.
« Reply #20 on: June 09, 2025, 11:51:33 am »
OK  :-+
Didn't know you were using a fpga ... Well verilog.

 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 17830
  • Country: fr
Re: Assembler 'org' directive.
« Reply #21 on: June 09, 2025, 04:00:55 pm »
The TL;DR is that it highly depends on the assembler in question, there is no standard about "ORG" directives.
As you saw, some assemblers will properly pad data when using multiple ORG directives in the same source file, and many won't. I suspect that the simpler ones just deal with one ORG directive per source file and ignore any subsequent ones.
 

Offline ejeffrey

  • Super Contributor
  • ***
  • Posts: 4852
  • Country: us
Re: Assembler 'org' directive.
« Reply #22 on: June 09, 2025, 05:57:23 pm »
Also, if you want to accurately place multiple blocks of data in a single binary and resolve their references...

That is what linkers do.

If you switch to a workflow where you put the objects in specific sections and write a linker script that puts those sections at the right location then you will get what you expect and never have to use the .org directive at all.
 

Offline radiolistener

  • Super Contributor
  • ***
  • Posts: 5745
  • Country: Earth
Re: Assembler 'org' directive.
« Reply #23 on: June 09, 2025, 07:50:46 pm »
Using $FF as a fill value for unused blocks is considered good practice, as FLASH and UV-erasable EEPROM typically represent unwritten memory with $FF. This approach helps preserve the memory's lifespan, since writing $00 sets all bits to zero, which results in maximum wear on the memory cells.

You can use this way to do it:
Code: [Select]
    org     0x1000
    ret
block0_end:
   
    defs    block1_begin-block0_end, $ff
   
    org     0x1010
block1_begin:
    ret

result.hex:
Code: [Select]
:11000000C9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC96C
:00000001FF

result.lst:
Code: [Select]
1000:              org     0x1000
1000: C9          ret
1001:          block0_end:
                 
1001: FFFFFFFF     defs    block1_begin-block0_end, $ff
1005: FF...   
                 
                  org     0x1010
1010:          block1_begin:
1010: C9          ret
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf

 

- - -
-->