白黒地帯

ゲームとか色々、Twitterに書ききれないことなど。

【shapez】回路いろいろ その2(記憶装置など)


ついに私もLv1000 gangになりました。

ということでshapezの回路のこといろいろ第2段です。

目次

エンコーダー・デコーダー効率を考慮した図形によるデータ圧縮転送

前回はバイナリデータを図形信号として運ぶのに図形の有無で0/1を表すとか色で運ぶとか言いましたが…
結局実用上は図形で演算ができるメリットがあまりなく、さらにエンコーダー・デコーダー回路が大きくなると使いにくくなるので、結局以下のようなデータ図形化を使っています。
なお、データ図形化自体あまり実用的でないかなと思っていたら、MAMはとにかく回路スペースを小さくした過ぎて意外と使うことになりました。



下側が0/1→図形化エンコーダー、そこから上に伝送してデコーダーで図形→0/1に戻す回路になっています。

見ての通りですが、0=Ru 1=Cwとして、かつ右上→左上→左下→右下の順にデータを格納します。
順番がキー表記と異なるのは、デコード時に回転させながらAnalyzerにかける時に仮想RotatorがCWしかないのでCWで回る順にしているためです。
(結局上記のデコーダー回路では各回転分の仮想Rotatorを挟んでいるのであまり意味ないですが)(仮想CCW Rotatorはよ)
Analyzerで色が出る方向と形が出る方向が決まっているので、どちらからでも0/1を取り出せるように0と1で形も色も変えています。
例えば上記ではAnalyzerの左、色が出る方なので白色と同値比較していますが、Analyzerの右から出したい場合はCuと同値比較で同様に取り出せます。

上記例では1層ですが、もちろん4層使って16bit運べます(デコーダーにUnstackerが入りますが)
またあくまで図形なので桁が余ればその部位に任意のパーツもくっつけて伝送できます。
実際に自作MAMではそれを利用して1層4パーツの情報を、1パーツ=rgb3bit+形で構成される1層に変換して4パーツ分を重ねた1図形で伝送しています。

記憶装置(順序回路)

回路に信号を記憶しておけると色々便利です。
0/1を記憶すればいいのか、任意の信号を記憶したいのかにより向いてる回路やメリット・デメリットが異なるので分けて説明します。

1bitの記憶(ラッチ)

0/1の1bitの記憶ができる回路はラッチと呼ばれます。
一般的な論理回路分野の話なのでググると色々と情報が多く出てくるのも、任意の(=shapez特有の)信号記憶回路と違っていいところです。
全然知らないよ!って人はとりあえずSRラッチ・JKラッチ・Dラッチ・Tラッチあたりがどういうものか知っておくと便利かもしれません。

shapez内に基本的な論理ゲートがあるので真面目に各種ラッチを組んでもいいのですが、個人的オススメは下記に記載されているTラッチ(相当)回路を使うこと。
shapezio.fandom.com


組んでスイッチをカチカチしてみるとわかりますが、スイッチが0→1になるたびにXOR回路の出力に記憶されているデータが0→1→0→…と切り替わります。
一般的なTラッチ回路と中身は全く違いますが、動作はTラッチそのものです。
※ただしこのままTラッチと呼ぶと素直に組んだTラッチと区別しにくいので、以下ではshapez Tラッチ略してshTラッチと呼びます。

これをオススメする理由は動作が安定しているからです。もっと厳密には、1素子のパルスでも問題なく動作するからです。
上記wikiページにもいくつかの素直に組んだラッチが載っていますが、unstable(不安定)であると記載されているものもあります。
このような不安定な回路に1素子パルスを入れると期待通り動作しなかったり出力が細かく切り替わり続ける"発振"状態に入ることがありますが、shTラッチならその心配がありません。
(なおunstableとは書かれていないSRラッチも1素子パルスでは発振するのを確認しています)

でもSRラッチやJKラッチも使いたいのにshTラッチしかないんじゃ…と思いますよね。
まあ、shTラッチから他のラッチを作ればOKな話です。

順序回路の基礎的な情報ではSR→JK→D→Tと話が進んでいくのでTラッチから他のを作る話は見かけないですが、もう少し応用に踏み込んだ情報を探すと見つかります。
edu.isc.chubu.ac.jp
http://nw.tsuda.ac.jp/class/arch/c5.htmlnw.tsuda.ac.jp

結構楽しいので…ぜひプレイヤーの皆さん自身で一度作ってみてほしいですが、とりあえず自分が作った(そして正解と思われる)ものを置いておきます。

SRラッチはSに入力すればオン、Rに入力すればオフと、入力と結果の状態が決まっているのでタイマーのオンオフ記憶等に使いやすいです。
Dラッチは入力の記憶という意味では素直でわかりやすいですし、つなげると0001→0010→0100→…と循環するようなシフトレジスタを作れます。
Tラッチをつなげると2bitカウンターにもなります。
他にも一般的な論理回路において便利な仕組みがあればshapez内でもまたしかり、ですので色々使ってみてください。

余談

shTラッチから各ラッチを作ってみましたが…
まずJKラッチはCK入力なしのは作れないですね。CK入力がない場合、J=K=1の時にQ_n+1=~Q_nにならないといけないですが、J・Kが変化していないのにTを変化させることができないため、出力の変更にTの立ち上がりが必要なshTラッチでは仕様を満たせません。
ただCK入力のないJ=K=1のJKラッチは発振するだけなので…正直その条件を使うのかというと。J=K=1を使わないならSRラッチでいいですし。
ということで基本はCK入力とともに使うものだと思います。

またDラッチですが、CK=1にしっぱなしの状態でタイミングよく入力と出力が反転するとちゃんと入力が出力に入ってくれない(D=Qにならない)ことがあります。
例えばある瞬間に(D,Q)=(1,0)となったとすると、次にQが1になりますが、その瞬間ちょうど入力も0になり(D,Q)=(0,1)となったとします。
この時次に(D,Q)=(0,0)とならず、(D,Q)=(0,1)のままになってしまうことがあります。
これは(D,Q)が(1,0)→(0,1)という遷移をすると、その間でT=0になる瞬間がないため、上記のJKラッチの例と同じようにTの立ち上がりパルスが発生せず出力を変更できないためです。
入力が0になるまでにラグがある場合には(1,0)→(1,1)→(0,1)という遷移でTは1→0→1になるため仕様通り出力が変更されるのですが、タイミングによってはこのような状態になります。

対策というか、DラッチもCK=1にしっぱなしではなく変更のタイミングでクロック/パルス入力を入れる(同期型)利用をしたほうがいいでしょう。
この場合ならばCK=0になった時にかならずT=0を経由するので、CK=1になった時に必ず入力に応じて出力が更新されます。

任意の信号の記憶

0/1だけではなく色や図形信号も記憶できる回路はないの?と言われますと、あります。

このようにTransistor+1をぐるっと線で囲むと、そこに入力した信号は保持されます。

上記は信号保持部分だけですが、外から新しい入力を与えてやるならTransistorをつけるのがいいかと思います。
Transistorのサイド入力にスイッチやクロック入力を入れることにすると、Dラッチ風に記憶するタイミングとしない(保持する)タイミングを制御できます。


標準的な順序回路ではないのですがなにか名前が欲しいので、shapez Memory回路略してshMem回路と呼ぶことにします。

shMem回路の注意点

どんな信号も保持できて便利なshMem回路ですが、いくつか注意点があります。

1つ目は1素子のパルス入力では期待した動作をしないことがあることです。
例えば以下の図では、紫の図形がshMem回路に記憶されている状態で、新たにロケット図形(shMem回路の下部から入力)を記憶させようとしています。

shMem回路につながるTransistorのサイド入力に1素子パルスを入れて、記憶される図形を更新しようとしていますが…

実際にパルスを入れてみると、なんと保持されていた図形が消えてnilになってしまいました。

パルサーに1つTransistorを挟んでパルスの長さを2素子分にすると、ちゃんとパルスに合わせて記憶が更新されます。

このパルス長さの要求は意外なところで現れることもあります。
たとえば以下の図はshMem回路に0/1だけを入れることにするとDラッチとして扱えることを使って、循環シフトレジスタを作成したものになります。

パルスもちゃんと2素子分にしたので、スイッチをオンにすると今保持している001がシフトして010になるはずです。
ところが実際には…

2bit目はnilになってしまいました。
この場合、正しく動作させるには以下のようにshMem回路間にも遅延用のTransistorを挟んでやる必要があります。

もう1つ注意点は、1度何か信号を記憶するとnilを保持はできないことです。
一応上記の仕様で1素子パルスを入れてnilにすることはできなくはないのですが、標準的な動作は2素子分のパルスで、nilにする時は出力が存在するかチェックして1素子パルスを…と制御が複雑になります。
nilの記憶・出力をしたい場合はshMem回路では何か代わりの信号を割り当てておき、出力後に変換・取り扱いを変える方がスッキリするかと思います。

ということで、なんでも記憶できるからとshMem回路だけですべて状態管理や情報の記憶を行おうとすると逆にやりにくいことも多いです。
基本はshTラッチを元にしたラッチで記憶や装置制御を行い、何bitかの情報をまとめて伝送するときの記憶場所にshMem回路を使う…というような使い分けがいいのかなと思います。

シングルショットタイマー回路

せっかくLv1000 gangにもなったのでMAMの紹介をしたいのですが
全部一気にするとすごい量になるので、MAMのパーツとなる回路の説明をしたいと思います。

なんと呼ぶのが正確かわからず見出しに困ったのですが、ようするにキッチンタイマーのような「外部からの入力でオンになった後、X秒後に自動的にオフになる」ような回路です。
また、一度オンになった後に繰り返し入力がオンオフされても、オフになるまでの時間が変わったりはせず、かならず「オフ→オンに最初に変化してからX秒後」になります。
ここはPEと異なり、PEは入力がオンオフされると、「最後にオフになってからX秒後」に出力がオフになります。
また方針レベルの話ですが、PEはとにかくある程度の時間出力がオンになる時間が引き伸ばせればいいのですが、タイマー回路では何秒測るというのをある程度細かく設定したい、という需要の違いもあります。

このようなシングルショットタイマー回路ですが、物体とベルトを使う物理タイマーと回路のみで行う論理タイマーを作ったので両方説明します。

タイマーの注意

本題に入る前に…
この後タイマーで「X秒測る」ような表現が出てきますが、この場合のX秒はリアルX秒ではなくshapez内のX秒になります。
つまり、10秒と言ったら「8/sで運ばれている図形をすべてストレージに入れたら計時終了時に80個がストレージに入っている」時間なのです。
そして大抵リアルタイムではこれは10秒より長いです。
しかし、実用上はむしろshapez内での時間を測ってほしいのが普通なので、この仕様自体は正しいものです。
(例えば、8/sで10秒間出力する分の図形を貯めるのに4/sで流れてくる図形を20秒間貯めるなら、shapez内の時間で20秒測らなければいけません)

物理シングルショットタイマー


ちょっと周りに他のものもあるので見辛いですが、フィルター+ゴミ箱→大量のSplitterとMerger→ゴミ箱とベルトリーダーが接続されている2本のベルトが物理シングルショットタイマーになります。


下からぐるっと回り込んでいる緑線がタイマーオン入力になります。
ここに1が入力されるとタイマーオン状態になり計時が開始され、特定の時間経過後に自動的にタイマーオフになります。
タイマーがオンかオフかはSRラッチに保持されており、左の出力から出るのでそれを使用します。

タイマーがオンになってからオフになるまでの秒数Xは以下の式で計算できます。
X = 1/(Extractor個数*Extraction速度)*2^(Splitter数)

ちょっとこのままだとややこしいですが、Extraction速度の概ねの頭打ちである4/sにおいて、Extractorを3個・Splitterを7個置くと10.666...秒でちょうど10秒くらい測れるので、これを基準にするのが考えやすいと思います。
Splitterを1つ増やすと測れる時間が2倍になります。Extractorの数を1/nにすると測れる時間がn倍になります。
なので20秒測りたければSplitterを1つ増やして8個に、30秒測りたければExtractorを1個に…と調整できます。

一応、よく使いそうな秒数とそれ用の設定リストを掲載します。

原理

見ただけでもわかるかもしれないですが、連続して置かれているSplitterとMergerを図形が通り抜ける時、Splitter側を最後まで通る(そしてベルトリーダーを通る)のは2^Splitter数に1回しかありません。
Splitterが2個なら4回に1回、3個なら8回に1回です。
一方、Extractorから図形が出てくる間隔を考えてみます。
逆に1秒あたり何個図形が出てくるかについては、Extractor個数*Extraction速度です。図形と図形の間の間隔はその逆数で1/Extractor個数*Extraction速度です。
図形と図形の間の間隔は1/(Extractor個数*Extraction)秒で、ベルトリーダーを通るには2^Splitter回に1回なので、最初に流れ始めてからベルトリーダー側を通るまでの時間は1/(Extractor個数*Extraction)*2^Splitterになります。

論理シングルショットタイマー

全体

各部分

使用方法はほぼ物理と同じで、タイマーオンオフを保持するSRラッチをオンにして計時をスタートします(画像2枚目真ん中上部のスイッチ部分)。
指定時間が経つとタイマーが自動でオフになります。タイマーのオンオフ状態はSRラッチの出力に出るのでそれを使用します。

必須ではないのですが、この作例では終端bitを調整できるようにしています。
5bit目以降左側に出てるTransistor+緑線がその機構で、スイッチ入力が1になっているところが終端bitになります。
画像の状態だと、回路上は8bitまでありますが5bitのところのスイッチが1なので5bitが終端でそこまでしか使いません。

この論理タイマーが測れる時間Xは以下のようになります。
X = 0.01674943*クロック回路素子数*2^bit数

式の0.016...となっている部分はおそらく正確には0.016666...=1/60秒なのですが、一応実測から求めた値を書いておきました。
(あまり回数を試せてなく、この式で求められる時間はあまり精度がよくないので大体を決めるのに使用して下さい)

大体10秒測るのであれば素子数19・5bitで10.184秒になります。
物理タイマーの例と同じようにbit数を1増やすと測れる時間が2倍になるので7bitにするとだいたい40秒が測れます。
bit数を増やさなくても素子数を増やして測る時間を伸ばすこともできますが、40個も50個も置くとスペース的にも取り回しもよくないです。
そのあたりも考えると200秒測るのには9bit欲しくなると思います。

原理

shTラッチを繋げたリップルカウンターでクロック回路が何周したか数えています。
素子の更新は1フレーム(1/60秒)で、それに素子数と2bitカウンターでのカウント数をかけたものが総計時時間になります。

タイマーがオンの間はクロック入力がカウンターに入り、カウントアップしていきます。
終端bitの立ち下がり=カウント終了を検知してSRラッチをオフにします。
タイマーがオフになるとクロック入力がカウンターに入らなくなり、さらにオフの間はshTラッチの出力(記憶保持部分)にTransistorで強制的に0がセットされるようになっています。

shTラッチへの値セット

余談的ですが、shTラッチの保持部分にTransistorで入力すると、クロック入力に関係なく保持する値を決められるので
今回のような0リセットの他、シフトレジスタで1bit循環させるのに初期値の000...001をセットしておく、等にも使えます。

ただしこれを利用してshTラッチをDラッチのように使うことはオススメしません。
これを利用したDラッチはCK入力が1素子パルスでは動作しません。

素直に、前述のT入力を変換したDラッチを使用するのが汎用的にはよいと思います。

シングルショットタイマー総評

自分のMAMでずっと使用していたのは物理式の方です。
画像を見てもらえればわかりますが物理式のほうがずっと回路が小さくなります。
このタイマーはMAMで作成した図形を指定時間貯めてから一気に放出…という仕組みの中で使っていたのですが、それをやりたい場所は他にも回路がひしめいているので回路スペースをとる論理タイマーは採用しにくかったです。

半ボツネタ:図形分配装置

シフトレジスタを使い00001→00010→00100→...と1を循環させ、フィルターと接続することで複数のベルトに対し順番に図形を流し込む機構。
Balancerを組み合わせなくても1入力n出力を任意に作れるように…と作ったのですが、だいたい等分にはなるもののちゃんと等分にはならない…
ノルマスループットに必要な分以上のストレージに分配しても実は問題ないということに気付いたのもあり、しばらく使ってましたが結局廃止しました。

見た目には面白いのと場面によっては使いようがあるかも?

おわりに

MAMのことを書こうと思ったんですが力尽きてきたのとこれ以上長くするとエターなりそうなので一度切ります。