目次
前
次
ニモニックコンバータ(Python)
学研の「大人の科学」シリーズの中に
4ビットのコンピュータGMC-4があります。
4ビットコンバータの命令一覧は、以下。
JUMP
KA
AO
CH
CY
AM
MA
M+
M-
TIA
AIA
CIA
TIY
AIY
CIY
CAL_CHNG
CAL_CMPL
CAL_DEM+
CAL_DEM-
CAL_DSPR
CAL_RSTR
CAL_SETR
CAL_SIFT
CAL_SUND
CAL_TIMR
4ビットコンピュータというので、命令を表現する
ニモニックが特殊です。Z80や6809のニモニックに
慣れた身としては、体に染み付いているニモニック
を使いたいもの。
既知のニモニックでプログラムを作成後、コンバータで
本来のニモニックコードに戻し、アセンブルすることを
目論見ました。
Z80ニモニックに似せて、独自アセンブリ言語を
定義し、対応表を作成します。
JUMP
JUMPは、80ワードあるプログラムメモリの任意の
番地に分岐するために使うので、通常のマイコンで
あれば「JR」を利用します。
JR ? → JUMP ?
と変換します。
オペランドは、分岐先アドレスとします。
KA
KAは、キーパッドのキーの値を、レジスタAに転送
するので、Z80ならば「LD」か「IN」という命令に
なります。
INA → KA
と変換します。
AO
AOは、レジスタAの値を2進LEDに転送します。
Z80ならば「LD」か「OUT」という命令に。
OUTA → AO
と変換します。
CH
CHは、レジスタ群(A,B,Y,Z)の値を、AとB、YとZの間で
交換します。Z80ならば「EX」に相当します。
EX → CH
と変換します。
CY
CYは、レジスタAとYの値を交換します。
SWAP → CY
と変換します。
AM
AMは、レジスタAの値をYレジスタで指定する
データメモリに保存します。
6809ならば「STA」に相当します。
STA → AM
と変換します。
MA
MAは、Yレジスタで指定するデータメモリの値を
レジスタAに転送します。
6809ならば「LDA」に相当します。
LDA → MA
と変換します。
M+
M+は、Yレジスタが指定するデータメモリの値を
レジスタAの値を加算して、Aに入れ直します。
ADDA (Y) → M+
と変換します。
M-
M-は、Yレジスタが指定するデータメモリの値から
レジスタAの値を減算して、Aに入れ直します。
SUBA (Y) → M-
と変換します。
TIA
TIAは、オペランドの値をレジスタAに保存します。
LDIA ? → TIA
と変換します。
AIA
AIAは、オペランドの値をレジスタAに加算し、結果を
レジスタAに入れ直します。
ADDIA ? → AIA
と変換します。
TIY
TIYは、オペランドの値をレジスタYに保存します。
LDIY ? → TIY
と変換します。
AIY
AIYは、オペランドの値をレジスタYに加算し、結果を
レジスタYに入れ直します。
ADDIY ? → AIY
と変換します。
CIA
CIAは、オペランドの値がレジスタAと一致するか
調べ、結果をフラグに反映させます。
CPA ? → CIA
と変換します。
CIY
CIYは、オペランドの値がレジスタYと一致するか
調べ、結果をフラグに反映させます。
CPY ? → CIY
と変換します。
CAL_RSTO
数字LEDを消灯します。
TURN_OFF → CAL_RSTO
と変換します。
CAL_SETR
2進LEDの指定ビットを点灯します。
ビットの指定は、レジスタYの値を使います。
BSET → CAL_SETR
と変換します。
CAL_RSTR
2進LEDの指定ビットを消灯します。
ビットの指定は、レジスタYの値を使います。
BCLR → CAL_RSTR
と変換します。
CAL_CMPL
レジスタAの1の補数(反転)を求めて、レジスタAに
入れ直します。
CPL → CAL_CMPL
と変換します。
CAL_CHNG
レジスタ群と裏レジスタ群の値を入れ替えます。
EXX → CAL_CHNG
と変換します。
CAL_SIFT
レジスタAの値を1ビット右にシフトし、レジスタAに
入れ直します。
SLL → CAL_SIFT
と変換します。
CAL_ENDS
ENDの際の音を鳴らします。
BEEP_END → CAL_ENDS
と変換します。
CAL_ERRS
ERRORの際の音を鳴らします。
BEEP_ERROR → CAL_ERRS
と変換します。
CAL_SHTS
CWの「・」に相当する時間だけ
音を鳴らします。
BEEP_DOT → CAL_SHTS
と変換します。
CAL_LONS
CWの「―」に相当する時間だけ
音を鳴らします。
BEEP_DASH → CAL_LONS
と変換します。
CAL_SUNS
サウンド音を出力します。
SOUND → CAL_SUNS
と変換します。
CAL_TIMR
レジスタAで指定した時間だけウエイトします。
WAIT → CAL_TIMR
と変換します。
CAL_DSPR
指定メモリ(5F、5E)の内容を2進LED
に表示します。
SHOW → CAL_DSPR
と変換します。
CAL_DEM+
Yレジスタに含まれている値をアドレスとして
1ニブルの値を取出し、レジスタAと加算します。
加算結果をメモリに格納します。
ADD (Y),A → CAL_DEM+
と変換します。
CAL_DEM-
Yレジスタに含まれている値をアドレスとして
1ニブルの値を取出し、レジスタAの値を減算。
減算結果をメモリに格納します。
SUB (Y),A → CAL_DEM-
と変換します。
独自アセンブリ言語のニモニックとGMS-4の
ニモニックの対応表を作成します。
- JR ? JUMP ?
- INA KA
- OUTA AO
- EX CH
- SWAP CY
- LDA MA
- STA AM
- ADDA (Y) M+
- SUBA (Y) M-
- LDIA ? TIA ?
- ADDIA ? AIA ?
- LDIY ? TIY ?
- ADDIY ? AIY ?
- CPA ? CIA ?
- CPY ? CIY ?
- TURN_OFF CAL_RSTO
- BSET CAL_SETR
- BCLR CAL_RSTR
- CPL CAL_CMPL
- EXX CAL_CHNG
- SLL CAL_SIFT
- BEEP_END CAL_ENDS
- BEEP_ERROR CAL_ERRS
- BEEP_DOT CAL_SHTS
- BEEP_DASH CAL_LONS
- SOUND CAL_SUNS
- WAIT CAL_TIMR
- SHOW CAL_DSPR
- ADD (Y),A CAL_DEM+
- SUB (Y),A CAL_DEM-
コンバータは、文字列置換が基本なので、Pythonの
辞書を利用して対応表を作成します。
# generate disctionary
mdic = {}
mdic["JR"] = "JUMP"
mdic["INA"] = "KA"
mdic["OUTA"] = "AO"
mdic["EX"] = "CH"
mdic["SWAP"] = "CY"
mdic["LDA"] = "MA"
mdic["STA"] = "AM"
mdic["ADDA"] = "M+"
mdic["SUBA"] = "M-"
mdic["LDIA"] = "TIA"
mdic["ADDIA"] = "AIA"
mdic["LDIY"] = "TIY"
mdic["ADDIY"] = "AIY"
mdic["CPA"] = "CIA"
mdic["CPY"] = "CIY"
mdic["TURN_OFF"] = "CAL_RSTO"
mdic["BSET"] = "CAL_SETR"
mdic["BCLR"] = "CAL_RSTR"
mdic["CPL"] = "CAL_CMPL"
mdic["EXX"] = "CAL_CHNG"
mdic["SLL"] = "CAL_SIFT"
mdic["BEEP_END"] = "CAL_ENDS"
mdic["BEEP_ERROR"] = "CAL_ERRS"
mdic["BEEP_DOT"] = "CAL_SHTS"
mdic["BEEP_DASH"] = "CAL_LONS"
mdic["SOUND"] = "CAL_SUNS"
mdic["WAIT"] = "CAL_TIMR"
mdic["SHOW"] = "CAL_DSPR"
mdic["ADD"] = "CAL_DEM+"
mdic["SUB"] = "CAL_DEM-"
print mdic
辞書ができたかを確認すると、以下。
簡単なプログラムを作成して、ニモニックの
置換ができることを確認します。
テスト用プログラムを次のように定義します。
INA
OUTA
LDIY 1
LDIA 2
ADDIA 3
ADDIY 4
JR 2
ファイルからプログラムを読込み、リストの
中に1行ごとに要素として格納します。
この処理をスクリプトで記述します。
# open
fin = open('tst.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 )
print alist
動かしてみると、次のようになります。
リストの要素を取出してから、文字列に変換するので
要素をひとつずつ取出す処理を付加します。
# open
fin = open('tst.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 :
acode = []
tmp = e.split(' ')
for ee in tmp :
if ee != '' :
acode.append(ee)
print acode
命令を取出せているかを、確認します。
リストから文字列に変換しておきます。
# open
fin = open('tst.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 :
acode = []
tmp = e.split(' ')
for ee in tmp :
if ee != '' :
acode.append(ee)
# instruction
car = acode[0]
# oprand
cdr = ""
if len(acode) > 1 :
cdr = acode[1]
# concatenate
tmp = car + " " + cdr
print tmp
変換がうまくいっているのかを確認です。
命令をGMC-4のニモニックに置換します。
置換は、関数を定義して対応します。
また、パラメータを必要とする命令かも
関数で判定します。
def convInstruction(x):
# default
result = "*** unknown code ***"
# dictionary has target strings
if mdic.get(x) != None :
result = mdic[x]
return result
def hasOprand(x):
result = False
if x == "LDIA" or x == "ADDIA" :
result = True
if x == "LDIY" or x == "ADDIY" :
result = True
if x == "CPA" or x == "CPY" :
result = True
if x == "JR" :
result = True
return result
独自定義のニモニックではない場合、それを
メッセージで使えるようにします。
この関数を含めるとコンバータが完成します。
#
def convInstruction(x):
# default
result = "*** unknown code ***"
# dictionary has target strings
if mdic.get(x) != None :
result = mdic[x]
return result
def hasOprand(x):
result = False
if x == "LDIA" or x == "ADDIA" :
result = True
if x == "LDIY" or x == "ADDIY" :
result = True
if x == "CPA" or x == "CPY" :
result = True
if x == "JR" :
result = True
return result
# generate disctionary
mdic = {}
mdic["JR"] = "JUMP"
mdic["INA"] = "KA"
mdic["OUTA"] = "AO"
mdic["EX"] = "CH"
mdic["SWAP"] = "CY"
mdic["LDA"] = "MA"
mdic["STA"] = "AM"
mdic["ADDA"] = "M+"
mdic["SUBA"] = "M-"
mdic["LDIA"] = "TIA"
mdic["ADDIA"] = "AIA"
mdic["LDIY"] = "TIY"
mdic["ADDIY"] = "AIY"
mdic["CPA"] = "CIA"
mdic["CPY"] = "CIY"
mdic["TURN_OFF"] = "CAL_RSTO"
mdic["BSET"] = "CAL_SETR"
mdic["BCLR"] = "CAL_RSTR"
mdic["CPL"] = "CAL_CMPL"
mdic["EXX"] = "CAL_CHNG"
mdic["SLL"] = "CAL_SIFT"
mdic["BEEP_END"] = "CAL_ENDS"
mdic["BEEP_ERROR"] = "CAL_ERRS"
mdic["BEEP_DOT"] = "CAL_SHTS"
mdic["BEEP_DASH"] = "CAL_LONS"
mdic["SOUND"] = "CAL_SUNS"
mdic["WAIT"] = "CAL_TIMR"
mdic["SHOW"] = "CAL_DSPR"
mdic["ADD"] = "CAL_DEM+"
mdic["SUB"] = "CAL_DEM-"
# open
fin = open('tst.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 :
acode = []
tmp = e.split(' ')
for ee in tmp :
if ee != '' :
acode.append(ee)
# instruction
car = acode[0]
# oprand
cdr = ""
# ? instruction has operand
if len(acode) > 1 :
if hasOprand(car) == True :
cdr = acode[1]
# concatenate
tmp = convInstruction(car) + " " + cdr
print tmp
定義されていないニモニックを含めたときの
動作を確認してみます。
すべての命令を変換できているのかを
次のソースコードでチェックします。
INA
OUTA
EX
SWAP
LDA
STA
ADDA
SUBA
LDIA 0
ADDIA 1
LDIY 2
ADDIY 3
CPA 4
CPY 5
TURN_OFF
BSET
BCLR
CPL
EXX
SLL
BEEP_END
BEEP_ERROR
BEEP_DOT
BEEP_DASH
SOUND
WAIT
SHOW
ADD (Y),A
SUB (Y),A
JR 0
I/Oリダイレクトを利用して、変換すると
次のようになります。
KA
AO
CH
CY
AM
MA
M+
M-
TIA 0
AIA 1
TIY 2
AIY 3
CIA 4
CIY 5
CAL_RSTO
CAL_SETR
CAL_RSTR
CAL_CMPL
CAL_CHNG
CAL_SIFT
CAL_ENDS
CAL_ERRS
CAL_SHTS
CAL_LONS
CAL_SUNS
CAL_TIMR
CAL_DSPR
CAL_DEM+
CAL_DEM-
JUMP 0
得られたGMC-4のプログラムは、専用アセンブラに
かけて16進数に変換します。
目次
前
次