次に TM03 のレジスタに関連した定義をします。
皆さん良くご存知のように、 この手の周辺機器のコントローラにはレジスタが内蔵されていて、 そのレジスタに READ するとコントローラの状態がわかったり、 WRITE すると所定の動作を行ったりします。 つまりOSのデバイスドライバなどは、 この手のレジスタを介して周辺機器を制御するわけですが、 エミュレータではターゲットプログラムのレジスタに対する操作を ちゃんとフォローできないといけないわけ。 少なくともデバイスドライバをだませるぐらいにはね。
● TM03 のレジスタマクロを定義する
ということで、
例の
TM03
の
マニュアル
を見てみたのですが
・・・
Unix
側のデバイスドライバ
(ht.c)
と突き合わせるとレジスタが足りないのです。
PDP-11
の場合、
TM03
は
RH11
や
RH70
といった
MASSBUS
アダプタを介して接続されるので、
これが何かをしているのかも知れないし、
TM03
がアップデートされてレジスタが追加されたのかも知れない
(あるいはその両方)
ですが、
その真偽のほどは棚に上げて、
ここでは
Unix
側のデバイスドライバと内容が一致した
../PDP10/pdp10_tu.c
のマクロをそのまま流用します。
$ cvs diff -u cvs diff: Diffing . Index: pdp11_tu.c =================================================================== RCS file: /wrk/simh/cvs/src/simh/pdp11e/pdp11_tu.c,v retrieving revision 1.7 diff -u -r1.7 pdp11_tu.c --- pdp11_tu.c 11 Dec 2003 03:52:18 -0000 1.7 +++ pdp11_tu.c 11 Dec 2003 04:20:46 -0000 @@ -8,6 +8,177 @@ #define TU_NUMDR 8 /* #drives */ +// TUCS1 (RW) 17772440 - control/status 1 + +#define CS1_GO CSR_GO // go +#define CS1_V_FNC 1 // function pos +#define CS1_M_FNC 037 // function mask +#define CS1_FNC (CS1_M_FNC << CS1_V_FNC) +#define FNC_NOP 000 // no operation +#define FNC_UNLOAD 001 // unload +#define FNC_REWIND 003 // rewind +#define FNC_FCLR 004 // formatter clear +#define FNC_RIP 010 // read in preset +#define FNC_ERASE 012 // erase tape +#define FNC_WREOF 013 // write tape mark +#define FNC_SPACEF 014 // space forward +#define FNC_SPACER 015 // space reverse +#define FNC_XFER 024 // >=? data xfr +#define FNC_WCHKF 024 // write check +#define FNC_WCHKR 027 // write check rev +#define FNC_WRITE 030 // write +#define FNC_READF 034 // read forward +#define FNC_READR 037 // read reverse +#define CS1_IE CSR_IE // int enable +#define CS1_DONE CSR_DONE // ready +#define CS1_V_UAE 8 // Unibus addr ext +#define CS1_M_UAE 03 +#define CS1_UAE (CS1_M_UAE << CS1_V_UAE) +#define CS1_DVA 0004000 // drive avail NI +#define CS1_MCPE 0020000 // Mbus par err NI +#define CS1_TRE 0040000 // transfer err +#define CS1_SC 0100000 // special cond +#define CS1_MBZ 0012000 +#define CS1_DRV (CS1_FNC | CS1_GO) +#define GET_FNC(x) (((x) >> CS1_V_FNC) & CS1_M_FNC) +#define GET_UAE(x) (((x) & CS1_UAE) << (16 - CS1_V_UAE)) + +// TUWC (--) 17772442 - word count + +// TUBA (--) 17772444 - base address + +#define BA_MBZ 0000001 // must be zero + +// TUFC (--) 17772446 - frame count + +// TUCS2 (--) 17772450 - control/status 2 + +#define CS2_V_FMTR 0 // formatter select +#define CS2_M_FMTR 07 +#define CS2_FMTR (CS2_M_FMTR << CS2_V_FMTR) +#define CS2_UAI 0000010 // addr inhibit NI +#define CS2_PAT 0000020 // parity test NI +#define CS2_CLR 0000040 // controller clear +#define CS2_IR 0000100 // input ready +#define CS2_OR 0000200 // output ready +#define CS2_MDPE 0000400 // Mbus par err NI +#define CS2_MXF 0001000 // missed xfer NI +#define CS2_PGE 0002000 // program err +#define CS2_NEM 0004000 // nx mem err +#define CS2_NEF 0010000 // nx fmter err +#define CS2_PE 0020000 // parity err NI +#define CS2_WCE 0040000 // write chk err NI +#define CS2_DLT 0100000 // data late NI +#define CS2_MBZ (CS2_CLR | CS2_WCE) +#define CS2_RW (CS2_FMTR | CS2_UAI | CS2_PAT | CS2_MXF | CS2_PE) +#define CS2_ERR (CS2_MDPE | CS2_MXF | CS2_PGE | CS2_NEM | \ + CS2_NEF | CS2_PE | CS2_DLT ) +#define GET_FMTR(x) (((x) >> CS2_V_FMTR) & CS2_M_FMTR) + +// TUFS (RO) 17772452 - formatter status +// + indicates kept in drive status +// ^ indicates calculated on the fly + +#define FS_SAT 0000001 // slave attention +#define FS_BOT 0000002 // ^beginning of tape +#define FS_TMK 0000004 // end of file +#define FS_ID 0000010 // ID burst detected +#define FS_SLOW 0000020 // slowing down NI +#define FS_PE 0000040 // ^PE status +#define FS_SSC 0000100 // slave stat change +#define FS_RDY 0000200 // ^formatter ready +#define FS_FPR 0000400 // formatter present +#define FS_EOT 0002000 // +end of tape +#define FS_WRL 0004000 // ^write locked +#define FS_MOL 0010000 // ^medium online +#define FS_PIP 0020000 // +pos in progress +#define FS_ERR 0040000 // ^error +#define FS_ATA 0100000 // attention active +#define FS_REW 0200000 // +rewinding + +#define FS_DYN (FS_ERR | FS_PIP | FS_MOL | FS_WRL | FS_EOT | \ + FS_RDY | FS_PE | FS_BOT) + +// TUER (RO) 17772454 - error register + +#define ER_ILF 0000001 // illegal func +#define ER_ILR 0000002 // illegal register +#define ER_RMR 0000004 // reg mod refused +#define ER_MCP 0000010 // Mbus cpar err NI +#define ER_FER 0000020 // format sel err +#define ER_MDP 0000040 // Mbus dpar err NI +#define ER_VPE 0000100 // vert parity err +#define ER_CRC 0000200 // CRC err NI +#define ER_NSG 0000400 // non std gap err NI +#define ER_FCE 0001000 // frame count err +#define ER_ITM 0002000 // inv tape mark NI +#define ER_NXF 0004000 // wlock or fnc err +#define ER_DTE 0010000 // time err NI +#define ER_OPI 0020000 // op incomplete +#define ER_UNS 0040000 // drive unsafe +#define ER_DCK 0100000 // data check NI + +// TUAS (RW) 17772456 - attention summary + +#define AS_U0 0000001 // unit 0 flag + +// TUCC (RO) 17772460 - check character, read only + +#define CC_MBZ 0177000 // must be zero + +// TUDB (--) 17772462 - data buffer + +// TUMR (RW) 17772464 - maintenance register + +#define MR_RW 0177637 // read/write + +// TUDT (RO) 17772466 - drive type + +#define DT_TAPE 0040000 // tape +#define DT_PRES 0002000 // slave present +#define DT_TM03 0000040 // TM03 formatter +#define DT_OFF 0000010 // drive off +#define DT_TE16 0000011 // TE16 +#define DT_TU45 0000012 // TU45 +#define DT_TU77 0000014 // TU77 + +// TUSN (RO) 17772470 - serial number + +// TUTC (RW) 17772472 - tape control register + +#define TC_V_UNIT 0 // unit select +#define TC_M_UNIT 07 +#define TC_V_EVN 0000010 // even parity +#define TC_V_FMT 4 // format select +#define TC_M_FMT 017 +//#define TC_10C 00 // PDP-10 core dump +//#define TC_IND 03 // industry standard +#define TC_V_DEN 8 // density select +#define TC_M_DEN 07 +#define TC_800 3 // 800 bpi +#define TC_1600 4 // 1600 bpi +#define TC_AER 0010000 // abort on error +#define TC_SAC 0020000 // slave addr change +#define TC_FCS 0040000 // frame count status +#define TC_ACC 0100000 // accelerating NI +#define TC_RW 0013777 +#define TC_MBZ 0004000 +#define GET_DEN(x) (((x) >> TC_V_DEN) & TC_M_DEN) +#define GET_FMT(x) (((x) >> TC_V_FMT) & TC_M_FMT) +#define GET_DRV(x) (((x) >> TC_V_UNIT) & TC_M_UNIT) + +// TUBAE (--) 17772474 - bus address extension + +#define AE_M_MAE 0 /* addr ext pos */ +#define AE_V_MAE 077 /* addr ext mask */ +#define AE_MBZ 0177700 + +// TUCS3 (--) 17772476 - control/status 3 - unused except for duplicate IE + +#define CS3_IE CSR_IE // int enable +#define CS3_MBZ 0177660 + + t_stat tu_rd(int32 *data, int32 PA, int32 access); t_stat tu_wr(int32 data, int32 PA, int32 access); t_stat tu_svc(UNIT *uptr); $
ここで定義したレジスタのうち、
最後の2つ
(BAE, CS3)
は
../PDP10/pdp10_tu.c
には定義されていません。
これは
PDP-11/70
の
MASSBUS
アダプタ
RH70
特有のもので、
PDP-11/70
の
22 bit Addressing
に必要なものらしい。
この部分だけ
../PDP11/pdp11_rp.c
に定義されていたマクロを流用しました。
詳しくはまた後で、、、
● REG 構造体を記述する
エミュレータでは、
デバイスのレジスタは変数として定義されます。
で、レジスタへの読み出し/書き込みが発生すると、
エミュレートすべき振舞を行うと共に
該当する変数にその操作を行います。
先ほど保留にした
REG
構造体は、
SIMH
のコマンドモードで
この変数へのアクセス方法を定義するものなんですね。
ということで、 ここではデバイスのレジスタに相当する変数と REG 構造体の配列を定義します。 例によって ../PDP10/pdp10_tu.c と ../PDP11/pdp11_rp.c の内容を参考にします。
$ cvs diff -u cvs diff: Diffing . Index: pdp11_tu.c =================================================================== RCS file: /wrk/simh/cvs/src/simh/pdp11e/pdp11_tu.c,v retrieving revision 1.8 diff -u -r1.8 pdp11_tu.c --- pdp11_tu.c 11 Dec 2003 04:46:53 -0000 1.8 +++ pdp11_tu.c 11 Dec 2003 05:11:26 -0000 @@ -5,6 +5,10 @@ #include "pdp11_defs.h" #include "sim_tape.h" +extern int32 int_req[IPL_HLVL]; +extern int32 int_vec[IPL_HLVL][32]; + + #define TU_NUMDR 8 /* #drives */ @@ -179,6 +183,24 @@ #define CS3_MBZ 0177660 +int32 tucs1 = 0; // control/status 1 +int32 tuwc = 0; // word count +int32 tuba = 0; // bus address +int32 tufc = 0; // frame count +int32 tucs2 = 0; // control/status 2 +int32 tufs = 0; // formatter status +int32 tuer = 0; // error status +int32 tucc = 0; // check character +int32 tudb = 0; // data buffer +int32 tumr = 0; // maint register +int32 tutc = 0; // tape control +int32 tubae = 0; // bus address ext +int32 tucs3 = 0; // control/status 3 + +int32 tuiff = 0; // INTR flip/flop +int32 tu_stopioe = 1; // stop on error + + t_stat tu_rd(int32 *data, int32 PA, int32 access); t_stat tu_wr(int32 data, int32 PA, int32 access); t_stat tu_svc(UNIT *uptr); @@ -188,6 +210,7 @@ t_stat tu_detach(UNIT *uptr); t_stat tu_vlock(UNIT *uptr, int32 val, char *cptr, void *desc); + UNIT tu_unit[] = { { UDATA(&tu_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, { UDATA(&tu_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, @@ -200,6 +223,25 @@ }; REG tu_reg[] = { + { GRDATA(TUCS1, tucs1, DEV_RDX, 16, 0) }, + { GRDATA(TUWC, tuwc, DEV_RDX, 16, 0) }, + { GRDATA(TUBA, tuba, DEV_RDX, 16, 0) }, + { GRDATA(TUFC, tufc, DEV_RDX, 16, 0) }, + { GRDATA(TUCS2, tucs2, DEV_RDX, 16, 0) }, + { GRDATA(TUFS, tufs, DEV_RDX, 16, 0) }, + { GRDATA(TUER, tuer, DEV_RDX, 16, 0) }, + { GRDATA(TUCC, tucc, DEV_RDX, 16, 0) }, + { GRDATA(TUDB, tudb, DEV_RDX, 16, 0) }, + { GRDATA(TUMR, tumr, DEV_RDX, 16, 0) }, + { GRDATA(TUTC, tutc, DEV_RDX, 16, 0) }, + { GRDATA(TUMR, tumr, DEV_RDX, 16, 0) }, + { GRDATA(TUTC, tutc, DEV_RDX, 16, 0) }, + { FLDATA(IFF, tuiff, 0) }, + { FLDATA(INT, IREQ(TU), INT_V_RP) }, + { FLDATA(SC, tucs1, CSR_V_ERR) }, + { FLDATA(DONE, tucs1, CSR_V_DONE) }, + { FLDATA(IE, tucs1, CSR_V_IE) }, + { FLDATA(STOP_IOE, tu_stopioe, 0) }, { NULL } }; $
REG 構造体の定義のためには各種マクロを使います。 詳細は "Writing a Simulator for the SIMH System" を見てね。 なお、 REG 構造体にはレジスタに対応する変数だけでなく、 その他の変数も任意に定義することができます。 デバッグ目的で一時的に mogifier を追加することもアリです。
では、無事に登録できたかどうか確認しましょう。
$ make cc -g -DVM_PDP11 -I./ -I../ -I../PDP11 -c -o pdp11_tu.o pdp11_tu.c cc -o pdp11e pdp11_fp.o pdp11_cpu.o pdp11_dz.o pdp11_cis.o pdp11_lp.o pdp11_rk.o pdp11_rl.o pdp11_rp.o pdp11_rx.o pdp11_stddev.o pdp11_sys.o pdp11_tc.o pdp11_tm.o pdp11_ts.o pdp11_io.o pdp11_rq.o pdp11_tq.o pdp11_pclk.o pdp11_ry.o pdp11_pt.o pdp11_hk.o pdp11_xq.o pdp11_xu.o pdp11_tu.o scp.o scp_tty.o sim_sock.o sim_tmxr.o sim_ether.o sim_tape.o -lm $ ./pdp11e PDP-11 simulator V3.0-2 sim> ex tu state TUCS1: 000000 TUWC: 000000 TUBA: 000000 TUFC: 000000 TUCS2: 000000 TUFS: 000000 TUER: 000000 TUCC: 000000 TUDB: 000000 TUMR: 000000 TUTC: 000000 TUMR: 000000 TUTC: 000000 IFF: 0 INT: 0 SC: 0 DONE: 0 IE: 0 STOP_IOE: 1 sim> quit Goodbye $
どうやら無事動いているようです。
このように SIMH では examine コマンドを使うと デバイスローカルの変数も参照できます。 もちろん、 deposit コマンドで任意の値を設定することもできます。