パソコン活用研究5番街(Visual
Basic、Excel(VBA)、BASIC プログラミング研究)
VBアプリ 実例集 (PC2001ディスアセンブラ)
===============================================================================================
はじめに
「PC2001DisAsembler」は、NECのポケットPCであるPC2001の(CPUはμCom87)ディスアセンブラ&
おまけで、PC2001のBASIC(N20BASIC)の中間コード解析プログラム(アスキー形式の表示に変換)です。
これは、まったく個人的な用途のために作制したものです。
PC2001の内部ROM解析(マシン語)をWindows上で行うために作製しました。実用性という点では他の人に
役立つことは皆無に等しいと思いますが、同様のプログラムを組もうとしている人のコーディングの参考に
なる部分もあるだろうということで、取り上げてみました。
本稿に関連するページがいくつかありますが、本文中に都度紹介してありますので、参照して下さい。
ソースと実行ファイルのセットをダウウロードできます。-->PC21Disasm.lzh
Mickyさんが作成しているPC2001のエミュレータのページ-->PC2001エミュ
PC2001自体の解説や、ROMの解析-->PC2001エミュレータ PC2001ハード構成 スタートアップ
===============================================================================================
PC2001DisAsembler概要と使い方
PC2001DisAsembler はWindows上で、PC2001のマシン語をディスアセンブル、または中間コードの解析を
するためのものです。マシン語、中間コードのデータファイルを一般的なシケーシャルファイルの形で用意し
そのデータファイルを読み込んでディスアセンブルまたは解析を行います。
従って、ファーストステップとして何らかの形で解析のソースとなるデータファイルを作成していただく必要
があります。
なお、ディスアセンブル機能の部分は、もともとPC2001上で動かしていたディスアセンブルプログラムをベース
に移植したものなので、切り取ってちょっと手を加えれば、PC2001上で動かすものもすぐ作れると思います。
(従って、コードはGoto, Gosub を多様したいかにもBASICというコードそのままです。***筆者言い訳***)
【使い方】
1. PC2001のデータファイルの作制
まずは、ディスアセンブル(あるいは解析)したいマシン語、中間コード
のデータファイルを作制(取得)して下さい。データファイルは、一般的な
シケーシャルファイルの形式のものです。
筆者の場合は、RS232CでPC2001とWindowsマシンを接続して、
シリアル通信により必要なデータを取得し、Windowsマシン上にデータファイル
を作制しています。
PC2001側のRS232C送信プログラムの一例。
メモリー上のバイナリデータを文字データに変換してRS232Cに送信する
ぷろぐらむ。メモリー上の&HE000から&HE300までのデータを送信します。
10 Term J,0,4 ’データ長8ビット、パリティ無し、1200ボー
20 For I=&HE000 to &HE300
30 D=Peek(I) ’メモリーのバイナリデータを読む
40 Print %1,HEX$(D); ’文字型に変換してRS232Cから送信
50 Next
詳しくは筆者の関連サイト パソコン活用研究ラピュタ/RS232Cによるシリアル通信
を参照して下さい。
また、Windows上でのRS232C通信プログラムについては、VBアプリ実例集(RS232C通信)に
にVisual Basicでの作制例を掲載していますので、参考にして下さい。
2 データファイルの読み込み
メニュー「File」の「OPEN」をクリックすると、入力、保存フォームが
表示されますので、データファイルを選択して「入力」ボタンを押して下さい。
3 ディスアセンブル
メニュー「File」の「PC2001Disasm」をクリックすると、ディスアセンブル
を開始します。
4 中間コード解析
メニュー「File」の「PC2001Basic」をクリックすると、中間コードを解析
し、プログラムをTEXT表示します。なお、中間コード解析では、最初に
BASICプログラム格納開始番地、終了番地のデータが必要です。必ず、
最初にそれらのデータのあるデータファイルを準備して下さい。
PC2001では、BASICプログラム格納開始番地は、&HF90C,F90D
終了番地は &HF90E,&HF90Fに書き込まれています。データファイルの最初の
4個のデータは、このメモリーの値を入れるようにして下さい。
5 保存
ディスアセンブル、中間コード解析の結果を保存する場合は、「File」の
「Save」をクリックして下さい。入力、保存フォームが表示されますので
ファイル名を指定して「保存」ボタンを押して下さい。
PC2001関連の情報、およびRS232C通信関連の情報は筆者の関連サイト
パソコン活用研究ラピュタへの道にありますので、参照して下さい。
注意
プログラムの中でPathをきめうちしている部分があるので、全てのファイル
を c:\newgame\PC21Disasm というフォルダに置いて下さい。(アホなつくりですみません)
プログラムの解説
MODULE1.BAS module1.bas で配列p()をPublic変数として宣言します。配列p()は、データファイルから読み込まれたデータ を保存するためのものです。これで配列p()はプログラムのどこからでも使用できるようになります。 <コード> ' 宣言 Public p(10000)
FORM1.FRM
<FORM1のデザイン>
1) 宣言部 ディスアセンブラで使用するニモニックを入れる配列です。あとでdisasm.txtのデータをこの配列に 読み込みます <コード> Dim m0$(&H47), m8$(&H3F - &HE), mc$(&HCB - &HC0), md$(&HCB - &HC0), m5$(&H57 - &H51) Dim m6$(14), op$(6), M4$(&HD - 8), x5$(&H6F - &H65), m7$(7), r7$(6), r8$(6), m9$(14) 2) CLEAR TEXT ボタン <コード> '−−−CLEAR TEXTボタン−−− 'TEXT1のテキストをクリアします Private Sub Command1_Click() Text1.Text = "" End Sub 3) Form Load 変数の初期化を行い、disasm.txtを読み込んで、ディスアセンブラ用の配列にクニモニックを 読み込んでいきます。
<コード> Private Sub Form_Load() Open "C:\newgame\Disasm\disasm.txt" For Input As #1 '読み込み用にOPENする For i = 0 To &H47: Input #1, m0$(i): Next For i = 0 To &H3F - &HE: Input #1, m8$(i): Next For i = 0 To &HCB - &HC0: Input #1, mc$(i): Next For i = 0 To &HCB - &HC0: Input #1, md$(i): Next For i = 0 To &H57 - &H51: Input #1, m5$(i): Next For i = 0 To 14: Input #1, m6$(i): Next For i = 0 To 6: Input #1, op$(i): Next For i = 0 To &HD - 8: Input #1, M4$(i): Next For i = 0 To &H6F - &H65: Input #1, x5$(i): Next For i = 0 To 7: Input #1, m7$(i): Next For i = 0 To 6: Input #1, r7$(i): Next For i = 0 To 6: Input #1, r8$(i): Next For i = 0 To 14: Input #1, m9$(i): Next Close #1 End Sub 4) 「メニュー」 OPEN Form3を表示します。 <コード> '−−−メニュー open−−−− 'Form3の表示 Private Sub open_Click() Form3.Show End Sub 5) 「メニュー」 PC2001Basic PC2001 Basic中間コードを解析してアスキー形式(いわゆるTXT)に変換します。 P(0), P(1)にはBASICプログラムのStart Adressが入っている P(2), P(3)にはEnd Adressが入っている。 <コード> Private Sub Pc2001basic_Click() Dim a As Long, f(5) As Integer Text1.Text = "" n = 0: n1 = 0: e = 0 a = Val("&H" + p(0)) + Val("&h" + p(1)) * 256: Text1.Text = Text1.Text + "start address " + Hex$(a) + Chr$(13) + Chr$(10) a = Val("&h" + p(2)) + Val("&h" + p(3)) * 256: Text1.Text = Text1.Text + "end address " + Hex$(a) + Chr$(13) + Chr$(10) a = Val("&h" + p(5)) + Val("&h" + p(6)) * 256 - 57344: g = Val("&h" + p(7)) + Val("&h" + p(8)) * 256 Text1.Text = Text1.Text + Str$(g) + " ": i = 8 '以降中間コード解析部 '中間コードの構造 'リンクポインタ2Byte 行番号2Byte 中間コード本体 '変数aはリンクポインタをいれる。次のリンクポインタまで進んだらリンクポインタと行番号を新しいものに '更新−−>(1) '変数gは行番号 '変数dはBASIC中間コード '変数eはプログラム終了判定よう 0が6個以上続いたらプログラム終了
L60: Text1.Text = Text1.Text + w i = i + 1: d = Val("&h" + p(i)): w = "" If i - 4 = a Then '・・・・(1) a = Val("&h" + p(i)) + Val("&h" + p(i + 1)) * 256 - 57344 g = Val("&h" + p(i + 2)) + Val("&h" + p(i + 3)) * 256 Text1.Text = Text1.Text + Chr$(13) + Chr$(10) + Str$(g) + " " i = i + 3 GoTo L60 End If If d = 0 Then e = e + 1 Else e = 0 If e >= 6 Then GoTo L1500 '以降dの値を判定してwにBASICのコード(アスキー形式)を入力 'Select Case でひたすら判定、分岐処理をくりかえします。
Select Case d Case &H81 w = "END " Case &H82 w = "FOR " Case &H83 w = "NEXT " Case &H84 w = "DATA ": GoSub L1000 Case &H85 w = "INPUT " ' ****** 一部省略します *************** Case &H8F w = "REM ": GoSub L1000 Case &H91 w = "PRINT " Case &H95 w = "ON " Case &HAC w = "DEFINT " Case &H96 w = "WAIT " ' ****** 一部省略します *************** Case &HEB w = "DATE$ " Case &H11 To &H1A d = d - 17: w = Str$(d) Case &H22 w = Chr$(&H22): GoSub L1030 Case &HF i = i + 1: d = Val("&h" + p(i)): w = Str$(d) Case &HE, &H1C d = Val("&h" + p(i + 1)) + Val("&h" + p(i + 2)) * 256: w = Str$(d): i = i + 2 Case &HFF GoSub L1060 Case &H1D GoSub L1400 Case &HC w = "&H": d = Val("&h" + p(i + 1)) + Val("&h" + p(i + 2)) * 256: w = w + Hex$(d): i = i + 2 Case &HF0 w = " > " Case &HF1 w = " = " Case &HF2 w = " < " Case &HF3 w = " + " Case &HF4 w = " - " Case &HF6 w = " / " Case &HF5 w = " * " Case &HF9 w = " OR " Case &HF8 w = " AND " Case &HF7 w = "^" Case &HFA w = " XOR " Case &HFD w = " MOD " Case &HFE w = "\" Case Else If d >= &H20 Then w = Chr$(d) End Select GoTo L60 L1000: i = i + 1: d = Val("&h" + p(i)) If d = &H3A Or d = 0 Then w = w + " ": Return w = w + Chr$(d): GoTo L1000: L1030: i = i + 1: d = Val("&h" + p(i)) If d = &H22 Then w = w + Chr$(d): Return w = w + Chr$(d): GoTo L1030 L1060: i = i + 1: d = Val("&h" + p(i)) Select Case d Case &H81 w = "LEFT$" Case &H82 w = "RIGHT$" Case &H83 w = "MID$" Case &H84 w = "SGN" Case &H85 w = "INT" ' ****** 一部省略します *************** Case &H99 w = "OCT$" Case &H9A w = "HEX$" Case &HA2 w = "FIX$" End Select Return
'浮動小数点の解析部 L1400: fs = 0: f0 = Val("&h" + p(i + 4)) - &H80: f(0) = Val("&h" + p(i + 3)) + &H80: f(1) = Val("&h" + p(i + 2)): f(2) = Val("&h" + p(i + 1)) For j = 0 To 2 fs = fs + (f(j) And &H80) * 2 ^ (f0 - j * 8 - 8) + (f(j) And &H40) * 2 ^ (f0 - 8 - j * 8) + (f(j) And &H20) * 2 ^ (f0 - 8 - j * 8) + (f(j) And &H10) * 2 ^ (f0 - 8 - j * 8) + (f(j) And 8) * 2 ^ (f0 - 8 - j * 8) + (f(j) And 4) * 2 ^ (f0 - 8 - j * 8) + (f(j) And 2) * 2 ^ (f0 - 8 - j * 8) + (f(j) And 1) * 2 ^ (f0 - 8 - j * 8) Next i = i + 4: w = Str$(fs): Return L1500: End Sub 6) 「メニュー」 PC21Disasm PC2001の機械語をディスアセンブルします。 <コード> Private Sub pc21disasm_Click() a$ = InputBox("Topアドレスを入力して下さい", "Top Adress") ' 機械語のTop Adress入力 b$ = InputBox("bottomアドレスを入力して下さい", "Bottom adress") i = Val("&h" + a$): bt = Val("&h" + b$) + 1 Text1.Text = "" L600: a$ = Right$("000" + Hex$(i + k), 4) + " ": b$ = "": c$ = "": GoSub L1290 'ゼロパッティングの例 '4桁表示。左に0をつめる If d > &H47 Then GoTo L690 c$ = m0$(d) If c$ = "" Then GoTo L1210 L630: z0 = d And &HF If z0 = 4 Then GoSub L1330: GoTo L680 End If If (z0 = 0 And d <> 0) Then GoSub L1350: GoTo L680 End If If (z0 = 8 And d > &H20) Then GoSub L1350: GoTo L680 End If If z0 = 5 Then GoSub L1350: c$ = c$ + ",": GoSub L1310: GoTo L680 End If If z0 = 6 Or z0 = 7 Then GoSub L1310 L680: GoTo L1210 L690: If d <> &H48 Then GoTo L720 GoSub L1290 If d < &HE Or d > &H3F Then c$ = "db 48h," + Hex$(d) + "h": GoTo L1210 c$ = m8$(d - &HE): GoTo L1210 L720: If d <> &H4C Then GoTo L750 GoSub L1290 If d < &HC0 Or d > &HCB Then c$ = "db 4ch, " + Hex$(d) + "h": GoTo L1210 End If c$ = mc$(d - &HC0): GoTo L1210 L750: If d <> &H4D Then GoTo L770 GoSub L1290 If d < &HC0 Or d > &HCB Then c$ = "db 4dh, " + Hex$(d) + "h": GoTo L1210 End If c$ = md$(d - &HC0): GoTo L1210 L770: If d <> &H4E Then GoTo L775 GoSub L1290 c$ = "jre " + Right$("000" + Hex$(i + k + d), 4) + "h": GoTo L1210 L775: If d <> &H4F Then GoTo L780 GoSub L1290 c$ = "jre " + Right$("000" + Hex$(i + k + d - 256), 4) + "h": GoTo L1210 L780: If d < &H51 Or d > &H57 Then GoTo L800 c$ = m5$(d - &H51): GoTo L630 L800: If d <> &H60 Then GoTo L850 GoSub L1290 If d < &H88 Then GoTo L840 c$ = m6$(Int((d - &H88) / 8)) If c$ = "" Then GoTo L840 c$ = c$ + op$((d And &H7) - 1): GoTo L1210 L840: c$ = "db 60h," + Hex$(d) + "h": GoTo L1210 L850: If d = &H61 Then c$ = "daa": GoTo L1210 End If If d = &H62 Then c$ = "reti": GoTo L1210 If d <> &H64 Then GoTo L950 GoSub L1290 If d < &H88 Or d > &HDB Then GoTo L940 c$ = M4$(Int((d - &H88) / 16)) If c$ = "" Then GoTo L940 z0 = d And &HF If z0 > &HB Then GoTo L940 If (z0 = &HA) And ((Int(d / 16) = 8) Or (Int(d / 16) = 9)) Then GoTo L940 If z0 = 8 Then c$ = c$ + "pa," ElseIf z0 = 9 Then c$ = c$ + "pb," ElseIf z0 = 10 Then c$ = c$ + "pc," Else c$ = c$ + "mk," End If GoSub L1310: GoTo L1210 L940: c$ = "db 64h," + Hex$(d) + "h": GoTo L1210 L950: If d < &H65 Or d > &H6F Then GoTo L990 c$ = x5$(d - &H65) If c$ = "" Then GoTo L1210 If d = &H65 Then GoSub L1350: c$ = c$ + "," GoSub L1310: GoTo L1210 L990: If d <> &H70 Then GoTo L1120 GoSub L1290 If d < &HE Then GoTo L1110 If d > &H3F Then GoTo L1030 c$ = m7$((d And &H30) / 8 + (d And 1)): GoSub L1330: GoTo L1210 L1030: If (d < &H69) Or (d = &H78) Then GoTo L1110 If d > &H7F Then GoTo L1080 c$ = "mov$" If d < &H78 Then GoTo L1070 c1$ = r7$((d And &H7) - 1): GoSub L1330: c$ = c$ + "," + c1$: GoTo L1210 L1070: c$ = c$ + r7$((d And &H7) - 1) + ",": GoSub L1330: GoTo L1210 L1080: If d < &H89 Then GoTo L1110 If (d And &H7) = 0 Then GoTo L1110 c$ = m9$(Int((d - &H88) / 8)) + r8$((d And &H7) - 1): GoTo L1210 L1110: c$ = "db 70h," + Hex$(d) + "h": GoTo L1210 L1120: If d = &H73 Then c$ = "jb": GoTo L1210 If d = &H75 Then c$ = "eqiw ": GoSub L1350: c$ = c$ + ",": GoSub L1310: GoTo L1210 If d = &H76 Then c$ = "sbi a,": GoSub L1310: GoTo L1210 If d = &H77 Then c$ = "eqi a,": GoSub L1310: GoTo L1210 If (d >= &H78) And (d <= &H7F) Then cx = d And &HF: GoSub L1290: c$ = "calf " + Hex$(cx * 256 + d) + "h": GoTo L1210 End If If (d >= &H80) And (d <= &HBF) Then cx = d And &H3F: c$ = "calt " + Hex$(cx) + "h": GoTo L1210 If d < &HC0 Then GoTo L1200 cx = d And &H3F If cx >= &H20 Then cx = cx - &H40 c$ = "jr " + Right$("000" + Hex$(cx + i + k), 4) + "h": GoTo L1210 L1200: c$ = "db " + Hex$(d) + "h": GoTo L1220 L1210: If c$ = "" Then GoTo L1200 L1220: z1$ = "" For z0 = 1 To Len(c$) If Mid$(c$, z0, 1) = "$" Then z1$ = z1$ + " " ElseIf Mid$(c$, z0, 1) = "%" Then z1$ = z1$ + "," Else z1$ = z1$ + Mid$(c$, z0, 1) End If Next z0 a$ = Left$(a$ + " ", 18) + Left$(b$ + " ", 6) + z1$ Text1.Text = Text1.Text + a$ + Chr$(13) + Chr$(10) If i + k - bt < 0 Then GoTo L600 Else GoTo L1400 End If L1290: d = Val("&h" + p(k)): k = k + 1: da$ = Chr$(d) If da$ < " " Or da$ > "z" Then da$ = "." b$ = b$ + da$: a$ = a$ + Right$("0" + Hex$(d), 2) + " " Return L1310: GoSub L1290: c$ = c$ + Hex$(d) + "h": Return L1330: GoSub L1290: z0 = d: GoSub L1290: c$ = c$ + Hex$(d * 256 + z0) + "h": Return L1350: GoSub L1290: c$ = c$ + Right$(Hex$(&HFF00 + d), 4) + "h": Return L1400: End Sub
FORM3.FRM
<Form3のデザイン>
1) 保存ボタン Form1のText1の内容を指定したファイルに書き込み <コード> Private Sub Command1_Click() fname$ = File1.Path + "\" + Text1.Text Open fname$ For Output As #1 Print #1, Form1.Text1.Text Close #1 Unload Form3 End Sub 2) 入力ボタン 配列p()にデータを読み込みます <コード> Private Sub Command2_Click() fname$ = File1.Path & "\" & File1.filename Open fname$ For Input As #1 Do Until EOF(1) = True 'ファイルエンドまで読み込みをくりかえす Input #1, f$ p(t) = f$ texf$ = texf$ + f$ + "," t = t + 1 If (t Mod 16) = 0 Then 'データ16個毎に改行 texf$ = texf$ + Chr$(13) + Chr$(10) End If Loop Form1.Text1.Text = texf$ Close #1 Unload Form3 End Sub 3) ファイル名の指定 以下ファイルのパス、名前を指定する定番のやり方です <コード> Private Sub Dir1_Change() File1.Path = Dir1.Path End Sub Private Sub Drive1_Change() Dir1.Path = Drive1.Drive End Sub Private Sub File1_Click() Text1.Text = File1.filename End Sub
Disasm.txt
'PC2001のニモニック
'Form1のForm_load( )で読み込む
nop,,inx$sp,dcx$sp,lxi$sp%,aniw$,,ani$a%
ret,sio,mov$a%b,mov$a%c,mov$a%d,mov$a%e,mov$a%h,mov$a%l
,,inx$,dcx$b,lxi$b%,oriw$,xri$a%,ori$a%
rets,stm,mov$b%a,mov$c%a,mov$d%a,mov$e%a,mov$h%a,mov$l%a
inrw$,,inx$d,dcx$d,lxi$d%,gtiw$,adinc$a%,gti$a%
ldaw$,ldax$b,ldax$d,ldax$h,ldax$d+,ldax$h+,ldax$d-,ldax$h-
dcrw$,,inx$h,dcx$h,lxi$h%,ltiw$,suinb$a%,lti$a%
staw$,stax$b,stax$d,stax$h,stax$d+,stax$h+,stax$d-,stax$h-
,inr$a,inr$b,inr$c,call$,oniw$,adi$a%,oni$a%
push$v,pop$v
sknit$f0,sknit$ft,sknit$f1,,sknit$fs,,,
,,skn$cy,,skn$z,,push$b,pop$b
ei,,,,di,,,
,,clc,stc,,pex,push$d,pop$d
rll$a,rlr$a,,,,,,
rld,rrd,,,per,,push$h,pop$h
mov$a%pa,mov$a%pb,mov$a%pc,mov$a%mk,,,,,mov$a%s,mov$a%tmm,,mov$a%sc
mov$pa%a,mov$pb%a,,mov$mk%a,mov$mb%a,,mov$tm%a,,mov$s%a,mov$tmm%a,mov$sm%a,mov$sc%a
dcr$a,dcr$b,dcr$c,jmp$,offiw$,aci$a%,offi$a%
ana$,xra$,ora$,addnc$,gta$,subnb$,lta$,add$,,adc$,,sub$,nea$,sbb$,eqa$
a%a,a%b,a%c,a%d,a%e,a%h,a%l
ani$,ori$,,,oni$,offi$
neiw$,sui$a%,nei$a%,,mvi$a%,mvi$b%,mvi$c%,mvi$d%,mvi$e%,mvi$h%,mvi$l%
sspd$,lspd$,sbcd$,lbcd$,sded$,lded$,shld$,lhld$
a,b,c,d,e,h,l
b,d,h,d+,h+,d-,h-
anax$,xrax$,orax$,addncx$,gtax$,subnbx$,ltax$,addx$,onax$,adcx$,offax$,subx$,neax$,sbbx$,eqax$
TopPage > Visual BasIc&Excel活用研究目次