パソコン活用研究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活用研究目次