目次
前
次
TD-4アセンブラ(Python)
TD-4は「コンピュータの創り方」という書籍で扱われている
マイクロコンピュータです。
実用を考えたコンピュータではなく、コンピュータの動作
原理を学ぶために書かれた内容になっています。
スクリプト言語のテーマを探していたときに、偶然書店で
発見し、内容をみると電子工作に関する入門書にもなって
います。
大学、専門学校で、コンピュータのハード、ソフトを学ぶ
ためには、最適と考えました。ハードは、FPGAの中に入れ
ソフトをTcl/Tkで作成してみましたが、Tcl/Tkは、初学者
には敷居が高いようで、Pythonを使ってアセンブラ自作と
しました。
Pythonは、マルチプラットホームなので、Unix系OSで初版
を作成し、その後WindowsのDOS窓で動かしてみました。
どちらのOSでも、問題なく動きました。
アセンブラを作るには、対象となるアセンブリ言語の
記述フォーマットを知る必要があります。
TD-4アセンブリ言語のフォーマットは、以下でした。
命令、オペランドという並びになっているので
命令に合わせてオペランドの扱いをかえるよう
スクリプトを作成すればよいと判断できます。
オペランドを見ると、カンマで区切られている
場合、レジスタ名とレジスタ名、レジスタ名と
値の組み合わせになっていることがわかります。
1行に含まれる文字列を要素とするリストを
作成し、リストの要素で変換処理すればよい
と考えました。
命令とオペランドのパターンを組み合わせ
対応する16進数をテーブルから引き出して
変換すれば、アセンブラになると考えます。
命令とオペランドのパターンの場合分けをします。
テーブルは、Pythonの辞書でまとめていきます。
MOV
MOV命令は、次の4パターンがあります。
MOV A,Im
MOV B,Im
MOV A,B
MOV B,A
これらを0から3のパターンとして、次のように
記憶してテーブルを作成しておきます。
mdic["MOV A,?"] = 3
mdic["MOV B,?"] = 7
mdic["MOV A,B"] = 1
mdic["MOV B,A"] = 4
ADD
ADD命令は、次の2パターンがあります。
ADD A,Im
ADD B,Im
これらを2パターンとして、次のように
記憶してテーブルを作成しておきます。
mdic["ADD A,?"] = 0
mdic["ADD B,?"] = 5
IN
IN命令は、次の2パターンです。
IN A
IN B
これらを2パターンとして、次のように
記憶してテーブルを作成しておきます。
mdic["IN A"] = 2
mdic["IN B"] = 6
OUT
OUT命令は、次の2パターンです。
OUT Im
OUT B
これらを2パターンとして、次のように
記憶してテーブルを作成しておきます。
mdic["OUT ?"] = 11
mdic["OUT B"] = 9
JMP
JMP命令は、オペランドをひとつ持ち、即値を
利用するので、オペランドによる分類はしない
で済ませます。
辞書への登録だけにしておきます。
mdic["JMP"] = 15
JNC
JNC命令は、オペランドをひとつ持ち、即値を
利用するので、オペランドによる分類はしない
で済ませます。
辞書への登録だけにしておきます。
mdic["JNC"] = 14
辞書への登録処理を記述すると、以下です。
# generate disctionary
mdic = {}
mdic["MOV A,?"] = 3
mdic["MOV B,?"] = 7
mdic["MOV A,B"] = 1
mdic["MOV B,A"] = 4
mdic["ADD A,?"] = 0
mdic["ADD B,?"] = 5
mdic["IN A"] = 2
mdic["IN B"] = 6
mdic["OUT ?"] = 11
mdic["OUT B"] = 9
mdic["JMP"] = 15
mdic["JNC"] = 14
print mdic
辞書への登録ができているか確認しました。
アセンブリ言語で記述したプログラムを
ファイル名ta.asmにファイルに入れたと
して、読込み、行をリストの要素にする
コードを作成します。
# open
fin = open('ta.asm','r')
# get
line = fin.read()
# close
fin.close()
# generate list
glist = line.split('\n')
# delete space
alist = []
for e in glist :
if e != '' :
print alist
ファイルta.asmの内容は、以下。
OUT 15
MOV A,0
MOV B,1
OUT B
IN B
MOV A,B
ADD B,2
JNC 10
IN A
ADD A,2
MOV B,A
OUT B
JMP 0
動作を確認すると、次のようになります。
1行ごとに、命令とオペランドを見て、パターンに
分類していきます。
命令とオペランドに分割する処理を付加します。
# generate disctionary
mdic = {}
mdic["MOV A,?"] = 3
mdic["MOV B,?"] = 7
mdic["MOV A,B"] = 1
mdic["MOV B,A"] = 4
mdic["ADD A,?"] = 0
mdic["ADD B,?"] = 5
mdic["IN A"] = 2
mdic["IN B"] = 6
mdic["OUT ?"] = 11
mdic["OUT B"] = 9
mdic["JMP"] = 15
mdic["JNC"] = 14
# open
fin = open('ta.asm','r')
# get
line = fin.read()
# close
fin.close()
# generate list
glist = line.split('\n')
# delete space
alist = []
for e in glist :
if e != '' :
alist.append( e )
# separate
for e in alist :
# separate
acode = []
tmp = e.split(' ')
for ee in tmp :
if ee != '' :
acode.append(ee)
print acode
うまくできているかを確認します。
オペランドをパターン分けするので、パターン値と命令
を利用し、16進数コードを生成する関数を定義します。
def getPCode(x):
# opcode
xopc = x[0]
# operand
xopr = x[1]
# default
result = ""
car = ""
cdr = ""
# MOV
if xopc == "MOV" :
if xopr[0] == "A" and xopr[2] == "B" :
car = str(convHex(mdic["MOV A,B"]))
cdr = "0"
if xopr[0] == "A" and xopr[2] != "B" :
car = str(convHex(mdic["MOV A,?"]))
cdr = str(convHex(int(xopr[2:])))
if xopr[0] == "B" and xopr[2] == "A" :
car = str(convHex(mdic["MOV B,A"]))
cdr = "0"
if xopr[0] == "B" and xopr[2] != "A" :
car = str(convHex(mdic["MOV B,?"]))
cdr = str(convHex(int(xopr[2:])))
# ADD
if xopc == "ADD" :
cdr = str(convHex(int(xopr[2:])))
if xopr[0] == "A" :
car = str(convHex(mdic["ADD A,?"]))
if xopr[0] == "B" :
car = str(convHex(mdic["ADD B,?"]))
# IN
if xopc == "IN" :
cdr = "0"
if xopr == "A" :
car = str(convHex(mdic["IN A"]))
if xopr == "B" :
car = str(convHex(mdic["IN B"]))
# OUT
if xopc == "OUT" :
if xopr == "B" :
car = str(convHex(mdic["OUT B"]))
cdr = "0"
else :
car = str(convHex(mdic["OUT ?"]))
cdr = str(convHex(int(xopr)))
# JMP
if xopc == "JMP" :
car = str(convHex(mdic["JMP"]))
cdr = str(convHex(int(xopr)))
# JNC
if xopc == "JNC" :
car = str(convHex(mdic["JNC"]))
cdr = str(convHex(int(xopr)))
# concatenate
result = car + cdr
return result
数値を16進数に変換する関数を利用している
ので、タプルを利用して定義します。
def convHex(x) :
hx = ('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F')
return hx[x]
まとめると、以下となります。
#
def convHex(x) :
hx = ('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F')
return hx[x]
#
def getPCode(x):
# opcode
xopc = x[0]
# operand
xopr = x[1]
# default
result = ""
car = ""
cdr = ""
# MOV
if xopc == "MOV" :
if xopr[0] == "A" and xopr[2] == "B" :
car = str(convHex(mdic["MOV A,B"]))
cdr = "0"
if xopr[0] == "A" and xopr[2] != "B" :
car = str(convHex(mdic["MOV A,?"]))
cdr = str(convHex(int(xopr[2:])))
if xopr[0] == "B" and xopr[2] == "A" :
car = str(convHex(mdic["MOV B,A"]))
cdr = "0"
if xopr[0] == "B" and xopr[2] != "A" :
car = str(convHex(mdic["MOV B,?"]))
cdr = str(convHex(int(xopr[2:])))
# ADD
if xopc == "ADD" :
cdr = str(convHex(int(xopr[2:])))
if xopr[0] == "A" :
car = str(convHex(mdic["ADD A,?"]))
if xopr[0] == "B" :
car = str(convHex(mdic["ADD B,?"]))
# IN
if xopc == "IN" :
cdr = "0"
if xopr == "A" :
car = str(convHex(mdic["IN A"]))
if xopr == "B" :
car = str(convHex(mdic["IN B"]))
# OUT
if xopc == "OUT" :
if xopr == "B" :
car = str(convHex(mdic["OUT B"]))
cdr = "0"
else :
car = str(convHex(mdic["OUT ?"]))
cdr = str(convHex(int(xopr)))
# JMP
if xopc == "JMP" :
car = str(convHex(mdic["JMP"]))
cdr = str(convHex(int(xopr)))
# JNC
if xopc == "JNC" :
car = str(convHex(mdic["JNC"]))
cdr = str(convHex(int(xopr)))
# concatenate
result = car + cdr
return result
# generate disctionary
mdic = {}
mdic["MOV A,?"] = 3
mdic["MOV B,?"] = 7
mdic["MOV A,B"] = 1
mdic["MOV B,A"] = 4
mdic["ADD A,?"] = 0
mdic["ADD B,?"] = 5
mdic["IN A"] = 2
mdic["IN B"] = 6
mdic["OUT ?"] = 11
mdic["OUT B"] = 9
mdic["JMP"] = 15
mdic["JNC"] = 14
# open
fin = open('ta.asm','r')
# get
line = fin.read()
# close
fin.close()
# generate list
glist = line.split('\n')
# delete space
alist = []
for e in glist :
if e != '' :
alist.append( e )
# separate
for e in alist :
# separate
acode = []
tmp = e.split(' ')
for ee in tmp :
if ee != '' :
acode.append(ee)
# assemble
print acode,getPCode(acode)
使ってみた結果は、以下。
目次
前
次