友達に見せられた蓮コラと呼ばれる画像がトラウマのMotmuuです.
あの画像作ってる人は平気なんですかね...? あー痒くなってきました笑
今日は,記憶装置と呼ばれるものをPythonで実装していきたいと思います.
気になる方はこちらをご覧ください.
・#1 アルゴリズムとは
・#2 パーセプトロンとは
・#3 単純な論理回路
・#4 XORゲート
・#5 NANDは全ての論理ゲート
#開発環境
以下の環境で勉強していきたいと思います.
・Python 3.6.5 ・Mac OS X 10.13.2 ・Atom 1.10.2
サンプルコートはこちら
#記憶装置とは?
記憶装置と聞くとなんだかメタリックなものをイメージしますが,ここでは単純に記憶する機能があるものをさします.
ところで朝ごはん何食べましたか?
-> ぼくは食パンです
昨日いいことありました?
-> 授業が早く終わりました
昨日の授業で先生がpointと言っていたところ覚えていますか?
-> ...
こんな感じで過去のことを覚えておくことが記憶するということですね.
ちなみに3つ目の質問にバッチリ答えられた人はこれからの学習でこちらのサイトなども参考にするといいかもですね!
東芝 半導体&ストレージ製品 https://toshiba.semicon-storage.com/jp/design-support/e-learning/micro_intro/chap1/1274779.html
過去の状態を覚えておく回路を考えて行きましょう.
#情報記憶回路
情報記憶回路には,フリップフロップやランダムアクセスメモリ,リードオンリーメモリなどがあります.それぞれFF,RAM,ROMなどとかかれます.実際のマイクロプロセッサにはRAMやROMが使われますが,簡単のためにここではFFを扱います!
(難しいことは今回勉強しません!ごめんなさい...)
#記憶させるには?
回路に記憶させるのは難しそうですね....
でもちょっと考えてみましょう.ある入力を与えそれを記憶させる方法はいたってシンプルです.
出力と入力をくっつければいいのです!
...でも,それだと入力できませんね....
そこで,考案されたのがSRFFです!
入力としてSとRを与えます.
そしてSからの出力とRの入力のNORをRの出力とします
同様に,Rからの出力とSの入力のNORをSの出力とします
ここで出てきたSの出力とRの入力のNORをRの出力とします
....
というように動作して行きます.動作の様子は以下のようになります
S | R | 出力 | (出力) |
---|---|---|---|
0 | 0 | memo | memo |
0 | 1 | 0 | 1 |
1 | 0 | 1 | 0 |
1 | 1 | - | - |
SとRに0を入力しているうちは,出力は一定に保たれます(記憶されます)
Rに1を入力(reset)すると出力は0に,Sに1を入力(set)すると出力は1になります.
詳しいFFの説明は
東芝 半導体&ストレージ製品 https://toshiba.semicon-storage.com/jp/design-support/e-learning/micro_intro/chap1/1274779.html
をご覧いただければと思います.
ここでは,入力と出力に依存せず出力が一定にすることができるということが大事です.
これが記憶するということです.
#SRFFの実装
それではこれをPythonで実装して行きましょう.
(概要)
前の出力をQとして,QとRのNORをとります,この時の出力をQbarとしてQbarとSのNORをとります.
この動作によって得られて結果をこのサイクルでの出力Qとします.
次のサイクルではこの結果Qを取り込み,同様に出力します.
ff.py
# 論理ゲートをインポート
from gates import AND
from gates import NAND
from gates import OR
from gates import NOR
from gates import XOR
from gates import NOT
#
def srff(S,R,Q): # S = 1,R = 1は定義されていない
Q = NOR.NOR(R,(NOR.NOR(S,Q)))
return Q
ではTerminalに連続して出力してあげましょう
ff.py #続き
clock = (i % 2 for i in range(10)) #ジェネレータの作成
print('\n'+'='*10+'set状態の確認(R=0で固定)\n')
Q = 0 # 出力の初期化
print('( S,R,Q )')
for i in clock:
Q = srff(i,0,Q)
print('(',i,0,Q,')')
clock = (i % 2 for i in range(10)) #ジェネレータの作成
print('\n'+'='*10+'reset状態の確認(S=0で固定)\n')
Q = 1 # 出力の初期化
print('( S,R,Q )')
for i in clock:
Q = srff(0,i,Q)
print('(',0,i,Q,')')
出力です.
*********$ python ff.py
==========set状態の確認(R=0で固定)
( S,R,Q )
( 0 0 0 )
( 1 0 1 )
( 0 0 1 )
( 1 0 1 )
( 0 0 1 )
( 1 0 1 )
( 0 0 1 )
( 1 0 1 )
( 0 0 1 )
( 1 0 1 )
==========reset状態の確認(S=0で固定)
( S,R,Q )
( 0 0 1 )
( 0 1 0 )
( 0 0 0 )
( 0 1 0 )
( 0 0 0 )
( 0 1 0 )
( 0 0 0 )
( 0 1 0 )
( 0 0 0 )
( 0 1 0 )
出力結果からもわかるように,
setされるとRが0である限り,Sが変化しても出力はずっと1のまま
resetされるとSが0である限り,Rが変化しても出力はずっと0のままですね
ちなみに出力が1であってもresetされると出力が0になっています.(resetの方の結果の1列目です)
このようにNORゲートを用いることで,値を記憶する回路をつくることができました.
しかし,この回路ではS,Rともに1が入力されてしまった場合定義されていません.
これを反転状態にするようにパワーアップしたJKFF,マスタースレーブJKFFなどもありますので興味があれば調べてみてください.
#まとめ
このように記憶回路を構成できます.
この回路を複数個並べて0と1の状態をいくつも記憶できるようにしたのが レジスタ です.
例えば2進数8個分が記憶できるレジスタがあったとします.記憶されている様子は下のような感じですかね..
[ 0 ] [ 1 ] [ 0 ] [ 0 ] [ 1 ] [ 1 ] [ 1 ] [ 1 ]
これはなんと2進数の01001111(2),16進数の4Fですね.
すなわちレジスタは2進数以外の値も(形式上)記憶できます.そしてこの16進数というのは1ワードという単位で呼ばれコンピュータを制御するための命令1つ分です.
すなわちこのレジスタに命令を保存できます.例えばあの値とってきて!とか これとこれを足して!とかです.
もっと詳しく勉強したくなった方は,KUE-CHIP2という勉強用のマイクロプロセッサがありますので,そちらのエミュレータを使ってみるといいと思います.
実際に命令を16進数で入れてプログラムが動く様子をレジスタの値が変化する様子を確認できます.
@yasuo-ozuさまが記事を書いていらっしゃいました.
KEMU Emulator
http://emu.kemuide.openwaseda.net/core.html
KUE-CHIP2という教育用マイコンのエミュレータを作った話 (1)
https://qiita.com/yasuo-ozu/items/3972085cfa7995e95132
#最後に
「Pythonでコンピュータを作る」 はこれで終わりです.
0と1だけでコンピュータはできているということが,都市伝説のように聞こえていましたが,なんとなく納得できるようになりました... 先人がこのような発明を繰り返していまの便利な環境があると思うと,感謝しながらプログラムがかけますね笑