目次

GMC-4アセンブラ(Python)

 学研の「大人の科学」シリーズの中に、4ビットの
 マイクロコンピュータがあります。



 アセンブリ言語のニモニックをハンドアセンブルして
 16進数に変換してから、入力するのは面倒と思いました。

 面倒なことは、コンピュータにやらせればよいと
 考えて、スクリプト言語でアセンブラを作ること
 にしました。

 アセンブリ言語のニモニックとコードの対応は
 以下のようになっています。

 命令によっては、オペランド(パラメータ)を
 必要とするものがありますが、基本は1ニブル
 (ニブルは4ビット)。

 アセンブラは、ニモニックを数値に置換する
 プログラムと考えれば、簡単な変換の処理を
 スクリプトで記述すればよいとわかります。

 簡単なプログラムを記述し、GMC-4のキー入力が
 やりやすいように、CUIでの操作イメージを作って
 みます。



 利用したプログラムテキストは、以下。

  KA
  AO
  TIY 1
  TIA 2
  AIA 3
  JUMP 2

 GMC-4の仕様を調べると、オペランド(パラメータ)を
 必要とする命令は、次の7種でした。

 これらの命令は、2あるいは3ニブルのコードに
 変換します。3ニブルに変換するのはJUMPのみで
 この場合、独自変換処理を作ることにします。

 基本命令のほかに、システムが用意している
 サブルーチンを呼出し、使うこともあります。

 サブルーチンは、すべて2ニブルになるので
 アセンブラは、次の4処理に分割して、記述
 すればよいとわかります。

 ここまでわかったなら、必要なスクリプトを記述
 していきます。

 命令テーブル作成
  ニモニックの文字列と命令コードの数値は、1:1に
  対応します。変換に利用するテーブル(表)を辞書を
  利用して作成します。

# generate disctionary
mdic = {}

mdic["KA"]   = 0
mdic["AO"]   = 1
mdic["CH"]   = 2
mdic["CY"]   = 3
mdic["AM"]   = 4
mdic["MA"]   = 5
mdic["M+"]   = 6
mdic["M-"]   = 7
mdic["TIA"]  = 8
mdic["AIA"]  = 9
mdic["TIY"]  = 10
mdic["AIY"]  = 11
mdic["CIA"]  = 12
mdic["CIY"]  = 13
mdic["JUMP"] = 15

mdic["CAL_RSTO"] = 224
mdic["CAL_SETR"] = 225
mdic["CAL_RSTR"] = 226
mdic["CAL_CMPL"] = 228
mdic["CAL_CHNG"] = 229
mdic["CAL_SIFT"] = 230
mdic["CAL_ENDS"] = 231
mdic["CAL_ERRS"] = 232
mdic["CAL_SHTS"] = 233
mdic["CAL_LONS"] = 234
mdic["CAL_SUND"] = 235
mdic["CAL_TIMR"] = 236
mdic["CAL_DSPR"] = 237
mdic["CAL_DEM+"] = 238
mdic["CAL_DEM-"] = 239

print mdic

  辞書ができたかをチェックします。



 プログラム入力
  アセンブラは、ニモニックで指定した文字列を数値
  に変換するのが仕事。プログラムは、ファイル内に
  記述するので、1行ごとに分割し、リストに入れて
  から、1行ごとに変換します。

  ファイルからプログラムを入力し、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

 リストの要素が、1行を構成しているのかを
 見てみます。



 リストの各要素は、プログラムの1行に分割されて
 いると確認できました。

 ファイル名を、常に同じにしておき、既存のプログラムは
 別ファイル名にして保存するとします。

 アセンブル処理
  アセンブルは、4種類に分割して実現します。
  サブルーチンと基本命令に分けて、処理を記述して
  みます。

# delete space
def cmdCode(x):
  # loop
  result = [] 
  for e in x :
    if e != '' :
      result.append( e )

  return result

# 
def havOperand(x) :
  result = False
  if x == "TIA" or x == "AIA" :
    result = True 
  if x == "TIY" or x == "AIY" :
    result = True 
  if x == "CIY" or x == "CIA" :
    result = True 
  if x == "JUMP" :
    result = True 

  return result

# 
def convHex(x) :
  hx = ('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F')
  return hx[x]

# 
def convHex2(x) :
  # clear
  result = ""
  # separate
  dh = x / 16
  dl = x % 16
  # concatenate
  result += convHex(dh)
  result += convHex(dl)

  return result

#
def isSubCode(x) :
  result = False
  if len(x) > 4 :
    result = True

  return result

# generate disctionary
mdic = {}

mdic["KA"]   = 0
mdic["AO"]   = 1
mdic["CH"]   = 2
mdic["CY"]   = 3
mdic["AM"]   = 4
mdic["MA"]   = 5
mdic["M+"]   = 6
mdic["M-"]   = 7
mdic["TIA"]  = 8
mdic["AIA"]  = 9
mdic["TIY"]  = 10
mdic["AIY"]  = 11
mdic["CIA"]  = 12
mdic["CIY"]  = 13
mdic["JUMP"] = 15

mdic["CAL_RSTO"] = 224
mdic["CAL_SETR"] = 225
mdic["CAL_RSTR"] = 226
mdic["CAL_CMPL"] = 228
mdic["CAL_CHNG"] = 229
mdic["CAL_SIFT"] = 230
mdic["CAL_ENDS"] = 231
mdic["CAL_ERRS"] = 232
mdic["CAL_SHTS"] = 233
mdic["CAL_LONS"] = 234
mdic["CAL_SUND"] = 235
mdic["CAL_TIMR"] = 236
mdic["CAL_DSPR"] = 237
mdic["CAL_DEM+"] = 238
mdic["CAL_DEM-"] = 239

# 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

# convert
pc = 0
for e in alist :
  # get mnemonic
  tmp = cmdCode( e.split(' ') )
  # get instruction
  cmd = tmp[0]
  # judge
  if isSubCode(cmd) == True :
    # separate
    dh = int(mdic[cmd]) / 16
    dl = int(mdic[cmd]) % 16
    # first nibble
    print convHex2(pc),convHex( dh )
    pc = pc+1
    # second nibble
    print convHex2(pc),convHex( dl )
    pc = pc+1

  定義して利用した関数もありますが、実行すると
  次のようになります。



  サブルーチンが、2ニブルに変換されています。

  新たに定義した関数の内容を説明します。

  スペース削除
   1行の中には、命令とオペランドが記述されています。
   命令、オペランドに分割してから、数値に変換しますが
   スペースはない方が処理しやすいので、スペース削除の
   関数を定義しました。

def cmdCode(x):
  # loop
  result = [] 
  for e in x :
    if e != '' :
      result.append( e )

  return result

  サブルーチン命令の判定
   サブルーチン命令は、ニモニックの文字列だけで
   判定できます。該当する文字列ならば、論理値を
   返すようにしました。

def isSubCode(x) :
  result = False
  if len(x) > 4 :
    result = True

  return result

  数値から16進数数字列変換
   命令は、16進の1文字か2文字になるので
   タプルを利用して変換します。

# hexadecimal -> digit
def convHex(x) :
  hx = ('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F')
  return hx[x]

# hexadecimal -> digit
def convHex2(x) :
  # clear
  result = ""
  # separate
  dh = x / 16
  dl = x % 16
  # concatenate
  result += convHex(dh)
  result += convHex(dl)

  return result

  オペランドをもつ命令の判定
   1ニブルで表現できる命令と2ニブル以上になる命令は
   異なります。2ニブル以上となる命令か否かを論理値で
   返すようにしました。

def havOperand(x) :
  result = False
  if x == "TIA" or x == "AIA" :
    result = True
  if x == "TIY" or x == "AIY" :
    result = True
  if x == "CIY" or x == "CIA" :
    result = True
  if x == "JUMP" :
    result = True

  return result

  基本命令の処理を付加して、アセンブラを完成させました。

# delete space
def cmdCode(x):
  # loop
  result = [] 
  for e in x :
    if e != '' :
      result.append( e )

  return result

# 
def havOperand(x) :
  result = False
  if x == "TIA" or x == "AIA" :
    result = True
  if x == "TIY" or x == "AIY" :
    result = True
  if x == "CIY" or x == "CIA" :
    result = True
  if x == "JUMP" :
    result = True

  return result

#  hexadecimal -> digit
def convHex(x) :
  hx = ('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F')
  return hx[x]

#  hexadecimal -> digit
def convHex2(x) :
  # clear
  result = ""
  # separate
  dh = x / 16
  dl = x % 16
  # concatenate
  result += convHex(dh)
  result += convHex(dl)

  return result

# check subroutine
def isSubCode(x) :
  result = False
  if len(x) > 4 :
    result = True

  return result

# generate disctionary
mdic = {}

mdic["KA"]   = 0
mdic["AO"]   = 1
mdic["CH"]   = 2
mdic["CY"]   = 3
mdic["AM"]   = 4
mdic["MA"]   = 5
mdic["M+"]   = 6
mdic["M-"]   = 7
mdic["TIA"]  = 8
mdic["AIA"]  = 9
mdic["TIY"]  = 10
mdic["AIY"]  = 11
mdic["CIA"]  = 12
mdic["CIY"]  = 13
mdic["JUMP"] = 15

mdic["CAL_RSTO"] = 224
mdic["CAL_SETR"] = 225
mdic["CAL_RSTR"] = 226
mdic["CAL_CMPL"] = 228
mdic["CAL_CHNG"] = 229
mdic["CAL_SIFT"] = 230
mdic["CAL_ENDS"] = 231
mdic["CAL_ERRS"] = 232
mdic["CAL_SHTS"] = 233
mdic["CAL_LONS"] = 234
mdic["CAL_SUND"] = 235
mdic["CAL_TIMR"] = 236
mdic["CAL_DSPR"] = 237
mdic["CAL_DEM+"] = 238
mdic["CAL_DEM-"] = 239

# 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 )

# convert
pc = 0
for e in alist :
  # get mnemonic
  tmp = cmdCode( e.split(' ') )
  # get instruction
  cmd = tmp[0]
  # judge
  if isSubCode(cmd) == True :
    # separate
    dh = int(mdic[cmd]) / 16
    dl = int(mdic[cmd]) % 16
    # first nibble
    print convHex2(pc),convHex( dh )
    pc = pc+1
    # second nibble
    print convHex2(pc),convHex( dl )
    pc = pc+1
  else :
    #  first nibble
    print convHex2(pc),convHex( int(mdic[cmd]) )
    pc = pc + 1
    #  second nibble and third nibble
    if havOperand(cmd) == True :
      if cmd == "JUMP" :
        # separate upper and lower
        dh = int(tmp[1]) / 16
        dl = int(tmp[1]) % 16
        # second nibble
        print convHex2(pc),convHex(dh)
        pc = pc + 1
        # third nibble
        print convHex2(pc),convHex(dl)
        pc = pc + 1
      else :
        print convHex2(pc),convHex(int(tmp[1]))
        pc = pc + 1

 アセンブル結果は、I/Oリダイレクトを利用して
 テキストファイルに保存します。



 テキストファイルにした内容は、次のようになります。

00 0
01 1
02 A
03 1
04 8
05 2
06 9
07 3
08 E
09 8
0A E
0B 0
0C E
0D 1
0E E
0F 2
10 E
11 4
12 E
13 5
14 E
15 6
16 E
17 7
18 E
19 8
1A E
1B 9
1C E
1D A
1E E
1F B
20 E
21 C
22 E
23 D
24 E
25 E
26 E
27 F
28 F
29 1
2A 1

 アドレスは、2進数のLED表示になるので
 2桁の16進アドレスを0と1の組み合わせ
 にしておきます。変換は、次のスクリプト
 でよいでしょう。

#
def convBinary(x):
  hx = ('0000','0001','0010','0011','0100','0101','0110','0111','1000','1001','1010','1011','1100','1101','1110','1111')
  # separate
  dh = x / 16
  dl = x % 16
  result = ""
  result += hx[dh]
  result += hx[dl]

  return result[2:]

# open
fin = open('result.txt','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 )

for e in alist :
  tmp = e.split(' ')
  print convBinary(int(tmp[0],16)),tmp[1]

 このスクリプトで変換すると、以下となります。

000000 0
000001 1
000010 A
000011 1
000100 8
000101 2
000110 9
000111 3
001000 E
001001 8
001010 E
001011 0
001100 E
001101 1
001110 E
001111 2
010000 E
010001 4
010010 E
010011 5
010100 E
010101 6
010110 E
010111 7
011000 E
011001 8
011010 E
011011 9
011100 E
011101 A
011110 E
011111 B
100000 E
100001 C
100010 E
100011 D
100100 E
100101 E
100110 E
100111 F
101000 F
101001 1
101010 1

 2進数の6桁は、スライスを利用しました。


目次

inserted by FC2 system