home ホーム search 検索 -  login ログイン  | reload edit datainfo version cmd icon diff delete  | help ヘルプ

読書メモ/「CPUの創りかた」

読書メモ/「CPUの創りかた」

読書メモ / 「CPUの創りかた」
id: 852 所有者: msakamoto-sf    作成日: 2010-11-25 16:39:55
カテゴリ: Assembler 読書 

大学時代の2003年に初版本購入してから、電子工作部分で時間とられそうだからと、ずるずる本棚に積み上げていた書籍。
本書の評価は、Amazonレビューが全てを物語っている。

というわけで、実に7年間も「今読むべきか、先送りすべきか」とずるずる迷っていたのを、2日くらいで読みきってしまい、なんだか本書に対する姿勢がこれで良いのか軽い罪悪感を感じています。
・・・本当は電子回路の製作にも挑戦しようと思ってたんですよ。だからこそ、時間と根気が必要と思って、まとまった時間が取れるタイミングを狙ってずるずる引き延ばしてきちゃったんですが。

が、電子工作に片足突っ込んでた大学時代ならまだしも、ここ6年半田ごても握らず電子工作もしていない人間。
回路図だけじゃ、もうさすがに無理。諦めました。実体配線図+部品一式揃ったキットがあればやるかも。

実際の回路製作を抜きにしても、エミュレータが公開されてますので1bit単位で弄ってみて、機械語と戯れることも出来ます。
ソフトウェアオンリーの人でも楽しめるようにはなってますので、オススメ。

追記:後日、ROM部分をスポイル+モジュール化する事で製作ハードルを下げ、実際に製作してみました:


さすがに何も手を動かさないのは罪悪感が残ってスッキリしませんので、本書に出てくる機械語のエミュレータを自分で作ってみることにします。
今回はPythonで作ってみました。いろいろ手抜きをしていますが、特に大きな手抜きは「入力ポートのビットを途中で変更できない」点です。コマンドラインオプションで与えた値で固定されます。

$ python td4emu.py [-sN] [-iXXXX] file
-sN : 命令を実行するときのinterval-wait秒を指定。省略時は1秒。
-iXXXX : "1" or "0" で入力ポート4bitのON/OFFを指定。省略時は"0000"。
file : 機械語を保存したファイル名

機械語は、文字の"1", "0" で直接保存しちゃいます。一行一命令です。"1", "0", スペースのみ許可されます。スペースは実行時に削除されるので、適当に位置あわせなどに使います。
例(内容は適当です):

0010 0000
0000 0001
1110 0001
0110 0000
0101 0001
1001 0000
1110 0011
1111 0000

実行すると延々と動き続けます。Control+Cで終了します。
実行例(機械語の内容は適当です):

$ python td4emu.py -i1110 t01.txt
interval : 1 sec
input_port : 1110
source:
00100000
00000001
11100001
01100000
01010001
10010000
11100011
11110000
-----
hit ENTER to start:
[00] 0010 0000 =>  [A:1110],[B:0000],[C:0],[IP:0000],[OUT:0000]
[01] 0000 0001 =>  [A:1111],[B:0000],[C:0],[IP:0001],[OUT:0000]
[02] 1110 0001 =>  [A:1111],[B:0000],[C:0],[IP:0001],[OUT:0000]
[01] 0000 0001 =>  [A:0000],[B:0000],[C:1],[IP:0001],[OUT:0000]
[02] 1110 0001 =>  [A:0000],[B:0000],[C:0],[IP:0010],[OUT:0000]
Traceback (most recent call last):
  File "td4emu.py", line 159, in <module>
    time.sleep(interval_sleep)
KeyboardInterrupt

以下、ソースです。10進数→2進数文字列の変換にbin()関数を使ってますので、Python2.6以降が必要のはずです。
td4emu.py:

import sys
import string
import re
import time
 
if len(sys.argv) < 2:
  print "usage %s [-sN] [-i0000] file" % sys.argv[0]
  sys.exit(1)
 
interval_sleep = 1
input_port = '0000'
 
for arg in sys.argv[1:]:
 
  if 0 == arg.find('-i'):
    input_port = arg.replace('-i', '')
    if not re.match(r'[01]{4}', input_port):
      print "-iXXXX : only 0 or 1, 4char"
      sys.exit(1)
    continue
 
  if 0 == arg.find('-s'):
    interval_sleep = int(arg.replace('-s', ''))
    continue
 
  filename = arg
 
f = open(filename, 'r')
def op_strip(v):
  v = v.replace(' ', '')
  return string.strip(v)
opcodes = map(op_strip, f.readlines())
 
print "interval : %d sec" % interval_sleep
print "input_port : %s" % input_port
print "source:"
for opcode in opcodes:
  print opcode
print "-----"
raw_input("hit ENTER to start:")
 
reg = {
    'a':'0000', 
    'b':'0000', 
    'ip':'0000', 
    'c':False, 
    'out':'0000'
    }
 
def int2bin4(v):
  v = 15 & v
  t = bin(v)
  t = t.replace('0b', '')
  f = 4 - len(t)
  f = '0' * f
  return f + t
 
def op_mov_a(reg, im):
  reg['a'] = im
  reg['c'] = False
 
def op_mov_b(reg, im):
  reg['b'] = im
  reg['c'] = False
 
def op_mov_a_b(reg, im):
  reg['a'] = reg['b']
  reg['c'] = False
 
def op_mov_b_a(reg, im):
  reg['b'] = reg['a']
  reg['c'] = False
 
def op_add_a(reg, im):
  t1 = int(reg['a'], 2)
  t2 = int(im, 2)
  t3 = t1 + t2
  reg['c'] = False
  if 15 < t3:
    reg['c'] = True
  reg['a'] = int2bin4(t3)
 
def op_add_b(reg, im):
  t1 = int(reg['b'], 2)
  t2 = int(im, 2)
  t3 = t1 + t2
  reg['c'] = False
  if 15 < t3:
    reg['c'] = True
  reg['b'] = int2bin4(t3)
 
def op_in_a(reg, im):
  reg['a'] = input_port
  reg['c'] = False
 
def op_in_b(reg, im):
  reg['b'] = input_port
  reg['c'] = False
 
def op_out(reg, im):
  reg['out'] = im
  reg['c'] = False
 
def op_out_b(reg, im):
  reg['out'] = reg['b']
  reg['c'] = False
 
def op_jmp(reg, im):
  reg['ip'] = im
  reg['c'] = False
 
def op_jnc(reg, im):
  v = reg['c']
  reg['c'] = False
  if not v:
    reg['ip'] = im
 
op_dict = {
    '0011' : op_mov_a, 
    '0111' : op_mov_b,
    '0001' : op_mov_a_b,
    '0100' : op_mov_b_a,
    '0000' : op_add_a,
    '0101' : op_add_b,
    '0010' : op_in_a,
    '0110' : op_in_b,
    '1011' : op_out,
    '1001' : op_out_b,
    '1111' : op_jmp,
    '1110' : op_jnc,
    }
 
real_ip = 0
while True:
  if real_ip > len(opcodes) - 1:
    real_ip = 0
 
  reg['ip'] = int2bin4(real_ip)
  ip_old = reg['ip']
  cur_op = opcodes[real_ip]
  op = cur_op[0:4]
  im = cur_op[4:]
  if not (op in op_dict):
    print "unknown op : %s, addr : %s" % (op, real_ip)
    sys.exit(1)
 
  print "[%02d] %s %s => " % (real_ip, op, im), 
 
  op_dict[op](reg, im)
 
  if reg['ip'] != ip_old:
    real_ip = int(reg['ip'], 2)
  else:
    real_ip += 1
 
  print "[A:%s],[B:%s],[C:%s],[IP:%s],[OUT:%s]" % (
      reg['a'], reg['b'], ('1' if reg['c'] else '0'), reg['ip'], reg['out'])
 
  time.sleep(interval_sleep)

以上。


プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2010-12-08 20:54:00
md5:90c70f40406b66ee1191cc04aa74f9cd
sha1:d9c99d9795668a1de0ba343d9b41981bf94e5bba
コメント
コメントを投稿するにはログインして下さい。