Z80は8080には無かった相対ジャンプ命令が追加されましたが、6809と違い相対コールができません。なのでOS9のようなポジションインディペンデントコード(PIC)なモジュールが書きづらいです。
昔から議論されていることではありますが、PICは面白いのか?wちょっと考えてみました。
PICなコール(相対コール)をソフトで実現するためにはプログラムカウンタ(PC)の値を参照する必要があります。
Z80の命令セット上、コール時のスタックからPCの値を拾えます(それ以外にPCの値を参照する方法はないと思う)
PCの値さえ参照できれば相対値をコール時のコードに埋め込めば相対コールが実現できます。下記が相対コールのコード例です。'+'が付いている行はマクロ展開で生成された命令です。
Z80 relocatable call
MACRO-80 3.44 09-Dec-81 PAGE 1
;*********************************
; 8080/Z80 relocatable call test
; 2018/12/24 by skyriver
;*********************************
0028 RELRST equ 028h ; using RST for reloc code
; *** reloc call macro ***
rcall macro dest
ld de,dest - $ - 4
rst RELRST
endm
.z80
0000' aseg
org RELRST
0028 E1 pop hl
0029 E5 push hl
002A 19 add hl,de
002B E9 jp (hl)
org 0100h
0100 test: rcall proc
0100 11 0003 + ld de,proc - $ - 4
0103 EF + rst RELRST
0104 C3 0104 jp $
0107 00 proc: nop
0108 C9 ret
end
MACRO-80 3.44 09-Dec-81 PAGE S
Macros:
RCALL
Symbols:
0107 PROC 0028 RELRST 0100 TEST
No Fatal error(s)
|
机上検討段階でほとんど動作検証ができてしまっているようなものですが実機での確認結果が下記です。ZSIDDはZSIDに小文字シンボル対応と1行ダンプ表示のパッチを適用したものです。
参照)
3チップ構成Pic24CPMマイコン(その4)ZSIDで小文字のシンボルを使う方法その2
下記のダンプ表示のようにZSIDがRST 38Hを使っているので上のソースから生成したHEXファイルをZSIDではロードできないためSコマンドで手入力しています。
relocatable call code test
a>zsidd
ZSID VERS 1.4
#s28
0028 00 e1
0029 00 e5
002A 00 19
002B 00 e9
002C 00 .
#s100
0100 01 11
0101 F9 03
0102 21 00
0103 C3 ef
0104 3D c3
0105 01 04
0106 43 01
0107 4F 00
0108 50 c9
0109 59 .
#l28
0028 POP HL
0029 PUSH HL
002A ADD HL,DE
002B JP (HL)
002C NOP
002D NOP
002E NOP
002F NOP
0030 NOP
0031 NOP
0032 NOP
#l100
0100 LD DE,0003
0103 RST 28H
0104 JP 0104
0107 NOP
0108 RET
0109 LD E,C
010A LD D,D
010B LD C,C
010C LD B,A
010D LD C,B
010E LD D,H
#d0
0000: C3 03 FA 00 00 C3 00 CA 00 00 00 00 00 00 00 00 ................
0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0020: 00 00 00 00 00 00 00 00 E1 E5 19 E9 00 00 00 00 ................
0030: 00 00 00 00 00 00 00 00 C3 86 D8 00 00 00 00 00 ................
0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 20 20 20 .............
0060: 20 20 20 20 20 20 20 20 00 00 00 50 00 20 20 20 ...P.
0070: 20 20 20 20 20 20 20 20 00 00 00 00 00 FB EA FA ........
0080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
#x
----- A=00 B=0000 D=0000 H=0000 S=0100 P=0100
----- A'00 B'0000 D'0000 H'0000 X=0000 Y=0000 LD DE,0003
#t
----- A=00 B=0000 D=0000 H=0000 S=0100 P=0100
----- A'00 B'0000 D'0000 H'0000 X=0000 Y=0000 LD DE,0003
*0103
#t
----- A=00 B=0000 D=0003 H=0000 S=0100 P=0103
----- A'00 B'0000 D'0000 H'0000 X=0000 Y=0000 RST 28H
*0028
#t
----- A=00 B=0000 D=0003 H=0000 S=00FE P=0028
----- A'00 B'0000 D'0000 H'0000 X=0000 Y=0000 POP HL
*0029
#t
----- A=00 B=0000 D=0003 H=0104 S=0100 P=0029
----- A'00 B'0000 D'0000 H'0000 X=0000 Y=0000 PUSH HL
*002A
#t
----- A=00 B=0000 D=0003 H=0104 S=00FE P=002A
----- A'00 B'0000 D'0000 H'0000 X=0000 Y=0000 ADD HL,DE
*002B
#t
----- A=00 B=0000 D=0003 H=0107 S=00FE P=002B
----- A'00 B'0000 D'0000 H'0000 X=0000 Y=0000 JP (HL)
*0107
#t
----- A=00 B=0000 D=0003 H=0107 S=00FE P=0107
----- A'00 B'0000 D'0000 H'0000 X=0000 Y=0000 NOP
*0108
#t
----- A=00 B=0000 D=0003 H=0107 S=00FE P=0108
----- A'00 B'0000 D'0000 H'0000 X=0000 Y=0000 RET
*0104
#t
----- A=00 B=0000 D=0003 H=0107 S=0100 P=0104
----- A'00 B'0000 D'0000 H'0000 X=0000 Y=0000 JP 0104
*0104
#t
----- A=00 B=0000 D=0003 H=0107 S=0100 P=0104
----- A'00 B'0000 D'0000 H'0000 X=0000 Y=0000 JP 0104
*0104
#
|
想定通り動作することが実機で確認できました(すぐに動かせるCP/Mマシンがあると便利ですね^^)。
DEとHLレジスタを破壊してしまうし、コール命令が4バイトになってしまいますが、リロケータブルなコールが実現できます(必要な場面があまり思い浮かびませんがw)
また、上記の例ではRST命令を使っていますが、固定番地へのコール命令でも同様なことが可能です(この場合rcallは6バイト長になるけど)
★追記 2022/12/10
「
8080/Z80 リロケータブルコードの実験(その2)」の記事に DE/HL レジスタ非破壊のリロケータブルコールについて書きました。
下記の
[ 次へ ] からも飛べます。
[TOP] [ 前へ ] 連載記事
[ 次へ ]
posted by skyriver at 22:12|
Comment(0)
|
Z80
|

|