View Full Version : Is it safe to use RST 28h in CP/M assembly programs?

November 7th, 2016, 08:50 AM
Would any CP/M programmers out there care to comment on this scheme for implementing "call relative" functionality under CP/M? Is it safe? I can't see anything in the RST 28h vector prior to doing this on the CP/M implementation I'm doing it on, but I wanted to check...

.org 100h

; setup the RST 28 code ;
ld a,0e1h ; pop hl
ld (028h),a ;
ld a,0e5h ; push hl
ld (029h),a ;
ld a,0c9h ; ret
ld (02ah),a ;

; relative call to testfn
ld de,0004
rst 28h ; PC into HL
add hl,de
push hl ; to stack
jr testfn

; exit program (in CP/M, to CCP)
jp 0

testfn: ld a,0ffh ; do something
ret ; and return



So, first I copy a short subroutine to one of the RST vector addresses, 28h:

; RST 28h routine
0028 pop hl ; get return address into HL
0029 push hl ; restore return address to stack
002A ret ; ..and return

Now, when I issue the instruction RST 28h I get the value of the address immediately following the RST instruction in HL. From there I can calculate and push a return address onto the stack, then use JR to take me to the subroutine. When it hits the RET, I am back where I expect to be. This seems to work fine under ZSID and I expect it will be fine in any other code. Unless 28h is in use, which I think it isn't...

November 7th, 2016, 04:33 PM
Interrupt vectors are not used by CP/M, so from CP/M's perspective, it is OK to use RST 28h. Not to say, however, that someone's computer isn't configured with a device at interrupt vector 5 which would use RST 28h.

You can shorten the code at RST 28h to:

pop h

Which can be stored at 28h by

lxi h,0E9E1h ;H=PCHL, L=POP H
shld 28h

If you know the value of the stack pointer when doing this (e.g., this call is made when the stack is at its initialization value, say the equate "STACK"), then you can do this without RST 28h:

lxi h,0E9E1h ;H=PCHL, L=POP H
push h
call STACK-2 ;HL=address following call
lxi d,7 ;DE=offset past jr instruction
dad d
push h
jr testfn

And, of course, you could do this with a two byte fixed location as well to hold the PCHL, POP H.


November 7th, 2016, 07:03 PM
As Mike said, it depends on the system and its I/O routines. You're probably safe in most cases, but I wouldn't spec that at 100%.

Reminds me of the usage of the page 0 (direct memory) on the 6502 or the low-memory BIOS area on a PC. What's safe can vary.

What CP/M system (I can't think of it offhand) used a different vector for DDT breakpoints than the one at 0038H? Apparently it was already used for someone's keyboard routine. Memory fails me.

November 7th, 2016, 11:04 PM
Now that I do like.

pop HL
jp (HL)


I have to use a fixed address because the code that is calling it is going to be completely relocatable.

However, I may be better off leaving the calls as calls, and patching the call addresses once the code is relocated, because this wouldn't incur performance overhead. A bit of a headache if the code is changed though (because I would have to redo all the offsets to the called code).

Isn't this sort of how MOVCPM works?

November 8th, 2016, 08:59 AM
Very much so--I think I've referenced PRL files and how they originally got their start with MOVCPM, but became an integral part of MP/M and CP/M 3.0.

But PRL files use a bit map in which every bit corresponds to a memory location; one bits indicate that a page relocation offset should be added to the corresponding memory location.

If you have very few absolute memory references (as opposed to relative ones) you may want to employ a pointer list (2 bytes per reference) rather than a bitmap. This is unlikely in 8080 code which doesn't have relative jumps, but may be a consideration for Z80 code. The trick to quickly find this out is to assemble your program twice; the second time offset by 100H, then compare the two binaries.

The advantage of run-time relocation is that you don't have to incur a penalty for code that attempts to get around the relocation issue--no "tricks"; just write straight code.

November 8th, 2016, 09:13 AM
Yes indeedy. I may try that later on, but for now there are only a few relative calls so I'm going to try and get it going with RST 28h. It's the IDE driver, so I probably won't be happy with the lower performance (if I can perceive it). But as an exercise it'd be fun to use a bitmap. Looks easy enough.... (famous last words eh?) but I would like it to be easy to build, and automatic, so I can edit the code without updating any absolute address references manually.

November 8th, 2016, 11:12 AM
Jon I am planning to write IDE driver as well (in 8080 assembly).. when you are finished, and would be willing to share drop me a PM please.

November 9th, 2016, 10:39 AM
What CP/M system (I can't think of it offhand) used a different vector for DDT breakpoints than the one at 0038H? Apparently it was already used for someone's keyboard routine. Memory fails me.

Anything that used a Z80 in IM1 (such as the Spectrum +3) would need RST 38h for interrupts, so DDT / SID were modified to use RST 30h for breakpoints.