目次

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)

 使ってみた結果は、以下。




目次

inserted by FC2 system