• Please review our updated Terms and Rules here

Is it safe to use RST 28h in CP/M assembly programs?

JonB

Veteran Member
Joined
Jan 26, 2014
Messages
1,652
Location
South Herefordshire, UK
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...

Code:
	.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
	
	.end
	
	; EOF

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

Code:
; 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...
 
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:

Code:
        pop h
        pchl

Which can be stored at 28h by

Code:
        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:

Code:
        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.

Mike
 
Last edited:
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.
 
Now that I do like.

Code:
pop HL
jp (HL)

Neat!

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?
 
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.
 
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.
 
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.
 
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.
 
Back
Top