復活!CP/M ワンボードマイコンでCP/Mを!
CP/MがTK−80互換のワンボードマイコンの上で復活します
ND80ZVとMYCPU80の上でCP/Mが走ります!
[第460回]
●論理アドレスから物理アドレスへの変換(8086の場合)
前回のベースレジスタを使って20ビットのアドレスを算出するという説明を書いていて思い出しました。
これって8086のセグメントレジスタと同じやり方じゃないの?
ということで、ちょっと余談です。
8086は16ビットCPUですがアクセスできるメモリアドレスはZ8S180と同じ00000〜FFFFFの1MBです。
16ビットCPUなのでそれくらいのアドレスは命令で直接制御できるだろうと思われるかも知れませんが、意外にもそのあたりの機能に関しては8ビットCPUとそれほど変わりはありません。
なんと8ビットCPUと同様に16ビットのレジスタしか持っていないのです。
ということは8080やZ80、Z8S180と同様に通常のレジスタでアクセスできるメモリアドレスは0000〜FFFFの64KBに限られます。
それでは8086もZ8S180と同じようにメモリバンクによって1MBのメモリ空間をアクセスしているのかと言いますと、それはちょっと違います。
ただ論理メモリアドレスから物理メモリアドレスに変換する仕組みはZ8S180と似たところがあります。
16ビットのアドレスを20ビットのアドレスに変換するにはZ8S180と同じように、2つのレジスタの値を加算します。
8086ではメモリバンクではなくてセグメントという概念を使います。
セグメントはその中に論理的なアドレス0000〜FFFFをもつ64KBのメモリブロックです。
そのセグメントには使用目的別に、主として命令コードが置かれるコードセグメント(CS)、スタックとして使われるスタックセグメント(SS)、データ領域として使われるデータセグメント(DS)、それだけでは不足する場合に使われるエクストラセグメント(ES)の4つがあります。
セグメントレジスタを使って20ビットの物理アドレスを算出する方法はZ8S180での方法とよく似ています。
Z8S180のベースレジスタは8ビットですが8086のセグメントレジスタは16ビットです。
そして図のようにセグメントレジスタの値を4ビット左にずらして、命令中の16ビットの論理アドレスと加算して物理アドレスを求めます。
セグメントレジスタの値をベースにして、そこから64KBのメモリ空間がそのセグメントに割り当てられます。
セグメントレジスタの値は物理メモリ上で16バイトごとに指定することができます。
しかしもし各セグメントを16バイトごとに置いたとすると、各セグメントの中身が重なり合ってしまいます。
そうなるとたとえばデータセグメントにデータを書き込んだらコードセグメントのプログラムを破壊してしまった、というようなことが起きてしまう可能性があります。
ですからZ8S180のベースレジスタと同じように、セグメントレジスタもセグメントが重ならないように、64KBおきの値を入れるようにするのが普通です。
以上余談でした。
●メモリバンクテストプログラム
前回説明しましたバンクベースレジスタを使って1MBのメモリにバンクを切り換えながらテストデータを書き込んでいって、次にまた最初からバンクを切り換えながらメモリの値を読み出して正しく書き込まれているか比較チェックするプログラムです。
1MBのメモリを先頭から32KBづつに区切って、バンク0、バンク1、バンク2…としたとき、バンク0〜バンク2はシステムで使いますから、バンク3(物理アドレス18000〜18FFF)から後ろのアドレスを対象にします。
プログラムのうちバンクを切り換えてテストデータを書き込み、読み出すところは下のマシン語サブルーチンで行ないます。
結果の表示などを伴いますからその部分はBASICで書いて、マシン語のサブルーチンを呼び出して実行します。
2013/7/30 8:6 membkts.txt END=80AB ;;;memory bank test ; 13/7/30 ; ORG $8004 ; PA=$F440 PB=$F442 PC=$F444 PD=$F446 PE=$F448 ; 8004 C30A80 JP WR 8007 C34780 JP RDCK 800A 210000 WR:LD HL,$0000 800D ED4B42F4 LD BC,(PB) 8011 ED5B44F4 LD DE,(PC) 8015 3A40F4 LD A,(PA) 8018 ED DB ED 8019 39 DB 39;OUT0 [n],A 801A 39 DB 39 801B 73 WR2:LD (HL),E 801C 23 INC HL 801D 7C LD A,H 801E B7 OR A 801F FA3A80 JP M,WREND 8022 72 LD (HL),D 8023 23 INC HL 8024 7C LD A,H 8025 B7 OR A 8026 FA3A80 JP M,WREND 8029 71 LD (HL),C 802A 23 INC HL 802B 7C LD A,H 802C B7 OR A 802D FA3A80 JP M,WREND 8030 13 INC DE 8031 7A LD A,D 8032 B3 OR E 8033 C21B80 JP NZ,WR2 8036 0C INC C 8037 C31B80 JP WR2 803A ED4342F4 WREND:LD (PB),BC 803E ED5344F4 LD (PC),DE 8042 AF XOR A 8043 ED DB ED 8044 39 DB 39;OUT0 [n],A 8045 39 DB 39 8046 C9 RET ; 8047 210000 RDCK:LD HL,$0000 804A ED4B42F4 LD BC,(PB) 804E ED5B44F4 LD DE,(PC) 8052 3A40F4 LD A,(PA) 8055 ED DB ED 8056 39 DB 39;OUT0 [n],A 8057 39 DB 39 8058 7B RDCK2:LD A,E 8059 BE CP (HL) 805A C29980 JP NZ,RDERR 805D 23 INC HL 805E 7C LD A,H 805F B7 OR A 8060 FA8380 JP M,RDEND 8063 7A LD A,D 8064 BE CP (HL) 8065 C29980 JP NZ,RDERR 8068 23 INC HL 8069 7C LD A,H 806A B7 OR A 806B FA8380 JP M,RDEND 806E 79 LD A,C 806F BE CP (HL) 8070 C29980 JP NZ,RDERR 8073 23 INC HL 8074 7C LD A,H 8075 B7 OR A 8076 FA8380 JP M,RDEND 8079 13 INC DE 807A 7A LD A,D 807B B3 OR E 807C C25880 JP NZ,RDCK2 807F 0C INC C 8080 C35880 JP RDCK2 8083 ED4342F4 RDEND:LD (PB),BC 8087 ED5344F4 LD (PC),DE 808B 210000 LD HL,$0000 808E 2246F4 LD (PD),HL 8091 2248F4 LD (PE),HL 8094 AF RDEND2:XOR A 8095 ED DB ED 8096 39 DB 39;OUT0 [n],A 8097 39 DB 39 8098 C9 RET ; 8099 ED4342F4 RDERR:LD (PB),BC 809D ED5344F4 LD (PC),DE 80A1 2246F4 LD (PD),HL 80A4 6E LD L,(HL) 80A5 67 LD H,A 80A6 2248F4 LD (PE),HL 80A9 C39480 JP RDEND2 ; PA =F440 PB =F442 PC =F444 PD =F446 PE =F448 RDCK =8047 RDCK2 =8058 RDEND =8083 RDEND2 =8094 RDERR =8099 WR =800A WR2 =801B WREND =803A |
10 A=0 20 B%=0 30 C%=0 40 PRINT "*** write start" 50 FOR A%=$18 TO $78 STEP 8 60 PRINT HEX$(A%,2), 70 USR($8004) 80 PRINT "done" 90 NEXT A% 100 A%=2 110 B%=0 120 C%=0 130 PRINT "*** read check start" 140 FOR A%=$18 TO $78 STEP 8 150 PRINT HEX$(A%,2), 160 USR($8007) 170 IF E%<>0 GOTO 210 180 PRINT "done" 190 NEXT A% 200 STOP 210 PRINT "error!" 220 PRINT "b%=";HEX$(B%,4),"c%=";HEX$(C%,4), 230 PRINT "d%=";HEX$(D%,4),"e%=";HEX$(E%,4) |
>/ld membkts.bin,8004 loading MEMBKTS.BIN ...00a8(168)bytes loaded,from 8004 to 80AB >/load membktst.txt,8100 10 A=0 20 B%=0 30 C%=0 40 PRINT "*** write start" 50 FOR A%=$18 TO $78 STEP 8 60 PRINT HEX$(A%,2), 70 USR($8004) 80 PRINT "done" 90 NEXT A% 100 A%=2 110 B%=0 120 C%=0 130 PRINT "*** read check start" 140 FOR A%=$18 TO $78 STEP 8 150 PRINT HEX$(A%,2), 160 USR($8007) 170 IF E%<>0 GOTO 210 180 PRINT "done" 190 NEXT A% 200 STOP 210 PRINT "error!" 220 PRINT "b%=";HEX$(B%,4),"c%=";HEX$(C%,4), 230 PRINT "d%=";HEX$(D%,4),"e%=";HEX$(E%,4) data end >r. *** write start 18 done 20 done 28 done 30 done 38 done 40 done 48 done 50 done 58 done 60 done 68 done 70 done 78 done *** read check start 18 done 20 done 28 done 30 done 38 done 40 done 48 done 50 done 58 done 60 done 68 done 70 done 78 done break in 200 |