Question

I'm trying to use the venerable M80 and L80 tools on CP/M to build a ROM image. (It's for a CP/M emulator, hence why I'm using CP/M tools.)

Unfortunately L80 seems to be really crude --- AFAICT it just loads each object file at its absolute address, fixes it up, and then dumps everything from 0x0100 up out to disk. This means that object files that are based at addresses outside its own workspace don't appear to work at all (just producing an error message). My ROM has a base address of 0xd000, which is well outside this.

Does anyone know if it's possible to use M80 and L80 to do this, and if so, how? Alternatively can anyone recommend (and point me at!) a CP/M assembler/linker suite that will?

(Note that I'd like to avoid cross compiling, if possible.)

Was it helpful?

Solution

If you're just assembling one file, then you can use M80's .phase directive to have the assembler locate the output.

  .phase 0D000h

If you want to build several source files and link them at the end, then you can still use M80 but you'll need DRI's linker LINK.COM, which can be found in http://www.cpm.z80.de/download/pli80_13.zip. The LINK command line to use would be

LINK result=module1,module2,module3[LD000

(The nearest L80 equivalent would, I think, be

L80 /P:D000,module1,module2,module3,result/N/E

but then you have to remove 0xCF00 bytes from the start of the resulting file).

OTHER TIPS

Old question, but this may work for those who are still looking. I checked this out on my Ampro Little Board running 1980 M80/L80 on CP/M 2.2.

You can use the ASEG (absolute) directive in your starting .MAC file, specify 0D000H as the org, and then reference external modules. As long as those external modules don't include DSEG or PSEG directives you should be able to link them all together with 0D000H as the starting address. E.g.

; TEST.MAC
        ASEG
        ORG 0D000H
public  tstart
tstart: 
        ...
        call myfoo##   ; call routine myfoo in external module foo.rel
        ...
        end tstart

Assemble it:

M80 TEST,=TEST

Link it with foo.rel and use /X on the output to produce a .HEX file (TEST.HEX):

L80 TEST,FOO,TEST/N/X/E

If you examine the resulting .HEX file you should see the starting address is 0D000H. BTW: If you don't use /X option then L80 with /N/E will make a .COM with with all the code linked using an offset of 0D000H unless you also include a .phase directive. E.g.:

; TEST.MAC
        ASEG
        ORG 100H
        .phase 0D000H
public  tstart
tstart: 
        ...
        call myfoo##   ; call routine myfoo in external module foo.rel
        ...
        end tstart

Link to make a .COM instead of a .HEX:

L80 TEST,FOO,TEST/N/E   <== note no '/X'

You can't run it, but you can consider the .COM file is really a .BIN padded to the nearest 128 byte boundary (assuming that your CP/M is using the typical approach of allocating 128 byte blocks). You can confirm the result by doing a DUMP of the .COM file. If the code was very short it may also include leftover pieces of L80 loader code that wasn't overwritten by your code.

Note you can use also the ASEG approach with org 0100H to make a regular CP/M .COM. In that case you don't need to use .phase assuming the start of your code is at 100H.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top