目次

ニモニックコンバータ(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の
 ニモニックの対応表を作成します。

 コンバータは、文字列置換が基本なので、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進数に変換します。


目次

inserted by FC2 system