PDA

View Full Version : Can CP/M v2.2 LOAD a program at 0xC000?



smp
October 18th, 2016, 01:32 PM
I am exercising my new JAIR-8080 SBC in my IMSAI.

For the first time today I pulled in a source file for ASM code that wants to run at 0xC000. It's an old version of a small system monitor I hacked together years ago.

Anyway, the code assembles fine, and produces output as expected. Then, when I LOAD, I get a 52K COM file from a 4K HEX file, and the code does not run. The HEX file is perfectly fine. After some hours of tinkering with things, I redid the ORG to be 0x0100, and boom, everything assembles, loads, and runs just fine.

Is there something about LOAD under CP/M v2.2 that it does not want to locate programs at any place else than 0x0100?

Thanks,
smp

Chuck(G)
October 18th, 2016, 02:24 PM
Well yes, that's what LOAD does. Simple thing to do is to assemble the code at 0C000 and write an attached "stub" to move it up there when it loads for execution.

smp
October 18th, 2016, 03:54 PM
Well yes, that's what LOAD does. Simple thing to do is to assemble the code at 0C000 and write an attached "stub" to move it up there when it loads for execution.

Hi Chuck, thanks for your answer. Please let me be sure I understand it. LOAD *only* wants to locate programs to start 0x0100? That would be consistent with getting a 52K COM file, if LOAD believes the program should start at 0x0100, but my actual code is up at 0xC000.

I always thought that LOAD actually read the HEX file and located the program where it is supposed to go.

Thanks,
smp

Chuck(G)
October 18th, 2016, 05:14 PM
Maybe I wasn't clear--LOAD always generates a file designed to load at 100H. So if you ORG your assembly at C000H, LOAD will generate BF00H bytes of garbage before you see the start of your file. That's a lot of baggage to haul around.

But LOAD always assumes a start at 100H.

smp
October 18th, 2016, 06:03 PM
Maybe I wasn't clear--LOAD always generates a file designed to load at 100H.

Thanks very much, Chuck.

smp

Chuck(G)
October 18th, 2016, 07:52 PM
One way to get your assembly to work at a different address from 0100 is to ORG your assembly at 100H, but bias every jump by the relocation factor.

Here's an example


0100 ORG 0100H

START:
0100 1100C0 LXI D,REALORG ; where things will wind up
0103 211601 LXI H,LOADORG ; where the routine is assembled
0106 01E7FF LXI B,CODELEN ; how much we're moving
START2:
0109 7E MOV A,M
010A 12 STAX D
010B 23 INX H
010C 13 INX D
010D 0B DCX B
010E 78 MOV A,B
010F B1 ORA C
0110 C20901 JNZ START2 ; move things where they need to be
0113 C300C0 JMP REALORG ; enter our code

0116 = LOADORG EQU $ ; where LOAD will generate the code
C000 = REALORG EQU 0C000H ; where the code will end up
0005 = BDOS EQU 0005H ; BDOS entry
BEEA = RF EQU REALORG-LOADORG

DBSTART:
0116 110BC0 LXI D,MESSAGE+RF
0119 0E09 MVI C,9 ; BDOS show message
011B CD0500 CALL BDOS
011E C300C0 JMP DBSTART+RF

0121 48656C6C6FMESSAGE DB 'Hello world',13,10,'$' ; our message
FFE7 = CODELEN EQU LOADORG-$ ; How many bytes to move

012F END

The routine at DBSTART will assemble as if it was at C000, but in the LOAD-generated binary file, it's actually located at 0116H. When the routine is entered, it moves the code at DBSTART to 0C000H and jumps to it.

Some assemblers give you a way to deal with this automatically by maintaining two location counters--"ORG" where things are assembled and "LOC" where they will appear in memory after being moved.

smp
October 19th, 2016, 06:31 AM
One way to get your assembly to work at a different address from 0100 is to ORG your assembly at 100H, but bias every jump by the relocation factor.

Here's an example


Hi again, Chuck.

Thank you very much for the sample code. This will be very useful for me!

smp

JonB
October 19th, 2016, 11:30 AM
I use a similar technique for my CF card driver code.

The loader is in a separate source file to the driver code. It ORGs at 0100h.
The driver code is in another source file with ORG set to the load address.
I assemble them separately using Z80ASM.
Then I use a program called COMBINE.COM to join them, creating a new comfile.
The command line is COMBINE LOADER.COM DRIVER.COM DLOAD.COM
It's important to have the loader first, because COMBINE creates a com file that loads as usual at 100h.
To determine the start address of the driver code in the combined comfile, look at it with DUMP.COM. I define a string in the driver to help me locate it, although it's pretty easy to see.
The end address you can see in the driver code .LST assembler output.
You have to copy these into your loader code so it knows where to get the driver code from.

Hope that makes sense... if you need it I can supply you a copy of COMBINE.COM, and even some example code.

(When I get a chance I'll look closely at Chuck's example because it would be nice not to have two source files.)

Chuck(G)
October 19th, 2016, 01:29 PM
You'll note that mine simply computes a "relocation adjustment" and that any absolute references to memory locations (not Z80 JR, since that is PC-relative) have this added.

I should probably make one more example, showing how to write a loader for "page relocatable" files, which can be relocated to any 256-byte boundary. It should be very handy for "after boot" drive installation.

deramp5113
October 19th, 2016, 03:59 PM
Drifting a bit off the primary topic, you can also write self relocating 8080 code that binds the execution address at run time. For example, here's an Intel hex loader PROM that can run at most any 256 byte boundary you install it without having to change the PROM content at all. It even finds the highest free RAM possible into which to relocate itself.

http://deramp.com/downloads/altair/software/roms/custom_roms/HEXLOAD.ASM

Mike

Chuck(G)
October 19th, 2016, 04:26 PM
Not all that reliable, since it depends on a matching MSB of a two-byte address. You can get into trouble with a false match on an absolute non-relocatable address. That is, you need to code carefully to avoid pitfalls--and it gets more complicated with Z80 code.

Better to assemble twice 100H apart, then compare and build a bitmap of relocation. That way, there's no danger of a false positive.

deramp5113
October 19th, 2016, 06:45 PM
Not all that reliable, since it depends on a matching MSB of a two-byte address. You can get into trouble with a false match on an absolute non-relocatable address. That is, you need to code carefully to avoid pitfalls--and it gets more complicated with Z80 code.

Better to assemble twice 100H apart, then compare and build a bitmap of relocation. That way, there's no danger of a false positive.

To me, the more interesting aspect of the posted sample is the position independent nature of the code - not even the relocating loop has to be run at a specific address.

Since this particular application was creation of a small PROM, the relocation technique is quite reliable since the code won't change. This technique also requires less code space than a relocation bitmap and relocation code. This is important when trying to fit into a 256 byte PROM :)

An MSB of 0FDh is a good first choice for assembly-time ORG since 0FDh is not an 8080 opcode and is easier to keep unique than most other byte values.

For a more general solution - including the creation of custom MOVCPM's - yes, a relocation bitmap works well. I wrote a bitmap generator that takes two different ORG'd files and generates a bitmap file for appending onto the end of the MOVCPM.COM image for making a new MOVCPM for a custom BIOS.

Mike

Chuck(G)
October 19th, 2016, 07:34 PM
A bitmap generator was a standard part of MP/M--and (maybe) CP/M 3.0.

JohnElliott
October 20th, 2016, 02:11 PM
A bitmap generator was a standard part of MP/M--and (maybe) CP/M 3.0.

Yep, LINK filename[OP] generates a file with a relocation bitmap.

Chuck(G)
October 20th, 2016, 03:15 PM
If you use LINK, it goes without saying that you need to use RMAC to generate the object. The other way is to manually use ASM to generate a HEX, then edit the ORGs in the file to adjust by a 100H offset, then run GENMOD on them. A little bit more awkward but it gets the job done.

Personally, I don't understand why more people don't use the more advanced DRI tools. If you need a HEX file, there's always GENHEX.

JohnElliott
October 20th, 2016, 03:51 PM
And going back to the original question, LINK can also build a file with an arbitrary load address: LINK filename[LC000