[Z88dk-users] z80asm - multiple org statements in single source file

Bridge to the z88dk-users mailing list
Post Reply
gazsp
Member
Posts: 13
Joined: Sat Jun 19, 2010 5:07 pm

[Z88dk-users] z80asm - multiple org statements in single source file

Post by gazsp »

Hi all,

Is there any way to use multiple org statements in a single source file with z80asm?

I’ve got three sections of code I want in RAM, but need them to start at predetermined addresses. Using org multiple times at the moment gives me the error ‘ORG redefined’.

Do I need to split the files up and link them to get a final binary?

Cheers,
Gaz.
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, SlashDot.org! http://sdm.link/slashdot
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

Hi all,

Is there any way to use multiple org statements in a single source file with z80asm?

I?ve got three sections of code I want in RAM, but need them to start at predetermined addresses. Using org multiple times at the moment gives me the error ?ORG redefined?.

Do I need to split the files up and link them to get a final binary?
The assembler organizes output into SECTIONs. You can have up to one ORG per SECTION (I say up to because SECTIONs without ORG can be organized by the linker to be adjacent to each other).

So what you need to do is create three SECTIONs each with its own ORG and then your code should assign itself to the appropriate SECTION so that the linker will properly generate three output binaries.

The description of where SECTIONs are placed in memory is done with a memory map and the best way to communicate a memory map to the linker is to create the memory map in one place in the first file listed in an assemble (all asm) or compile (asm/c mix) line.

A contrived example composed of three different asm files:



"mmap.asm"

defb 0 ;; why this is here is mentioned below

SECTION REGION1
org 0x8000

SECTION REGION2
org 0xa000

SECTION REGION3
org 0xb000



"file1.asm"

SECTION REGION1
PUBLIC count_up

count_up: defb 1,2,3,4

SECTION REGION2
PUBLIC count_down

count_down: defb 100,99,98,97

SECTION REGION3
PUBLIC negative

negative:

ex de,hl
ld hl,0
xor a
sbc hl,de
ret

SECTION REGION1

defb 5, 6, 7, 8, 9, 10



"file2.asm"

SECTION REGION1

defb 11, 12, 13, 14

SECTION REGION3

PUBLIC invert
EXTERN negative

invert:

ld a,l
cpl
ld l,a
ld a,h
cpl
ld h,a
jp negative


And then assemble with:

zcc +zx -vn --no-crt mmap.asm file1.asm file2.asm -o out

will produce four binaries:

out.bin
the unnamed section

out_REGION1.bin
org 0x8000

out_REGION2.bin
org 0xa000

out_REGION3.bin
org 0xb000


Within file1.asm, section REGION1 is opened twice. The assigned bytes will be assigned to that section in the order encountered within that file so file1.asm's contribution to REGION1 will be "1,2,3,4,5,6,7,8,9,10".

file2.asm also contributes to REGION1. Whether its bytes appear before or after file1.asm's contribution to REGION1 depends on the order of the source files on the assemble/compile line. Since file2.asm appears after file1.asm in the zcc invocation above, file2.asm's data will appear after file1.asm's. Change the order and the sequence of bytes will be different. Usually you wouldn't care about order but in case it comes up, there you go.

You'll notice in mmap.asm that there is a single lone "defb 0" in there. This has to be there because otherwise mmap.asm will be empty and z80asm will *ignore* the file. If it ignores the file, there will be no memory map information and z80asm will just output a single file out.bin with all the sections stuck together. The "defb 0" is in an unnamed section and will be output as part of "out.bin". After an assemble or compile you can take a look at the size of that file and find out if you forgot to assign code or data to a section somewhere in your asm code. Because of the "defb 0" in this example, you will expect out.bin to be 1 byte in size; anything else indicates an error.


The assemble line I am using:

zcc +zx -vn --no-crt mmap.asm file1.asm file2.asm -o out

employs zcc instead of z80asm to guide the assembly. Besides zcc making things easy, the main reason I'd encourage this is that using zcc means you have access to macros in your asm code.

The actual target "+zx" doesn't matter with pure assembly and --no-crt. It will set up the library and include paths so that your assembly code can optionally use the target's library code. If you use library code, then choose the right target and compiler with -clib=(for the new lib) or optionally -compiler=sdcc (for the classic lib) even if you don't compile c because the library can be different depending on compiler.

A quick macro example:


"macro_ex.asm.m4"

include(`z88dk.m4')

Z88DK_FOR(`LOOP', 1, 100,
`
defb LOOP
'
)


Let's take a look at this in asm form by asking zcc to stop after the .m4 file is generated:

zcc +zx -vn -m4 macro_ex.asm.m4

The output will be maxro_ex.asm which will consist of "defb n" for n=1 to 100.

Macros end in .m4 and can be .asm.m4, .c.m4, .inc.m4, .h.m4. To use them just add them to the zcc compile line like every other source file. The one thing you must keep in mind is that foo.ext.m4 also reserves filename foo.ext in your source directory. This is because the macro expanded file is written to your source directory and will overwrite any file of that same name there. It has to be done this way to ensure include paths are properly processed.

The macro preprocessor used is m4 and z88dk defines some useful macros when z88dk.m4 is included:

https://github.com/z88dk/z88dk/blob/mas ... 4/z88dk.m4


A quick word on mixing with C: the zcc invocation used --no-crt:

zcc +zx -vn --no-crt mmap.asm file1.asm file2.asm -o out

Without that the assemble will include the target's (zx in this case) crt startup file as the first file. This crt file initializes c's environment and sets up a memory map and this would make it possible to use the library code without hitch (a pure asm project should then name its start point "_main").

If you want to add three sections with independent ORG you can still do that by defining those sections in your asm files with each section defining an ORG in exactly one place. You will get those three binaries out as before in addition to any generated as normal by the c compiler.



------------------------------------------------------------------------------
Announcing the Oxford Dictionaries API! The API offers world-renowned
dictionary content that is easy and intuitive to access. Sign up for an
account today to start using our lexical data to power your apps and
projects. Get started today and enter our developer competition.
http://sdm.link/oxford
gazsp
Member
Posts: 13
Joined: Sat Jun 19, 2010 5:07 pm

Post by gazsp »

Firstly, thank you for taking the time to write such a detailed response - it’s much appreciated.

One last question, how would I then get the separately compiled .o and .bin files into a single bin file (something I could load in to an emulator for example)?

Cheers,
Gaz.


------------------------------------------------------------------------------
Announcing the Oxford Dictionaries API! The API offers world-renowned
dictionary content that is easy and intuitive to access. Sign up for an
account today to start using our lexical data to power your apps and
projects. Get started today and enter our developer competition.
http://sdm.link/oxford
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

Firstly, thank you for taking the time to write such a detailed response - it's much appreciated.
It's no problem - eventually these postings will be pieced together into a FAQ. We suffer from a lack of documentation in the project.
One last question, how would I then get the separately compiled .o and .bin files into a single bin file (something I could load in to an emulator for example)?
.o are objects that are still relocatable -- the linker hasn't assigned it to an absolute address yet so these are not meant to be made part of any finish binary as-is.

The .bin files are the output with org address applied. How you get these into a specific target depends on the target. Often people have their own tools to process raw binaries and those can be used but z88dk also comes with its own toolset called "appmake". You may have seen c programs compiled using z88dk having a "-create-app" switch added to the compile line. All that does is add a processing step at the end that takes the output binary and puts it into a form suitable for the specific target being compiled for.

You can use appmake directly to get your output .bin into a form you need. I'm not sure which target you are assembling for? Is it a spectrum? (I seem to recognize your user name from some time ago but maybe I'm wrong :)

For the spectrum I use SpecEmu as emulator. With binaries, just drag and drop a .bin file to SpecEmu and it will ask you where to put it in memory. Enter the ORG address and it's there. Make sure you CLEAR below the ORG addresses before doing this so that Basic's data structures aren't accidentally overwritten and cause crash.

You can also make a big binary out of small ones, an example here:

1. Make a 32k blank bin file with zeroes in it

appmake +rom -s 32768 -f 0 -o final.bin

2. Write binaries into that file at the correct offset depending on the binaries' ORG addresses

appmake +inject -b final.bin -i out0.bin -s 256 -o dhry.bin
(inject file out0.bin at offset 256 in final.bin)

After adding all your binaries to "final.bin" you are left with one 32k .bin file that contains everything.

But for the zx usually you're loading from tape. You can use "appmake +zx" to make .tap files out of each .bin and then make a basic loader that loads them all in. The basic loader can be written in an emulator and saved to .tap or you can look up a spectrum tool like "bas2tap" ( https://bitbucket.org/CmGonzalez/pietro ... ?at=master for windows but you should be able to find it as source on the net) that can turn text files into basic .tap.

For a particular bin file foo.bin with org 40000, you can turn that into a tap without loader like this:

appmake +zx -b foo.bin --no-loader --org 40000 --blockname foo -o foo.tap

After all .bin are turned into .tap you would create the final tap by appending them together:

cat loader.tap foo1.tap foo2.tap foo3.tap > final.tap

And loader.tap would contain:

10 LOAD ""CODE (foo1)
20 LOAD ""CODE (foo2)
30 LOAD ""CODE (foo3)
40 RANDOMIZE USR xxxx (start program)

saved with SAVE "loader" LINE 1

For manipulating tap files, zx block editor may be worth a look.


If you are using c or c's crt (--no-crt not being used) you can just add "-create-app" to get an auto-loading tap out containing a basic loader and the main binary. Since you have more binaries, this isn't adequate.


It's hard to say the best way to go about things without knowing specific target and set of output files. If you need some more info, let us know!



------------------------------------------------------------------------------
Announcing the Oxford Dictionaries API! The API offers world-renowned
dictionary content that is easy and intuitive to access. Sign up for an
account today to start using our lexical data to power your apps and
projects. Get started today and enter our developer competition.
http://sdm.link/oxford
gazsp
Member
Posts: 13
Joined: Sat Jun 19, 2010 5:07 pm

Post by gazsp »

You can use appmake directly to get your output .bin into a form you need. I'm not sure which target you are assembling for? Is it a spectrum? (I seem to recognize your user name from some time ago but maybe I'm wrong :)
Yes, the target is a ZX Spectrum :-)
1. Make a 32k blank bin file with zeroes in it

appmake +rom -s 32768 -f 0 -o final.bin

2. Write binaries into that file at the correct offset depending on the binaries' ORG addresses

appmake +inject -b final.bin -i out0.bin -s 256 -o dhry.bin
(inject file out0.bin at offset 256 in final.bin)
This was the part I was missing.

Thanks again for the awesome responses!

Cheers,
Gaz.


------------------------------------------------------------------------------
Announcing the Oxford Dictionaries API! The API offers world-renowned
dictionary content that is easy and intuitive to access. Sign up for an
account today to start using our lexical data to power your apps and
projects. Get started today and enter our developer competition.
http://sdm.link/oxford
Post Reply