Posts Tagged with "Design"

既に発行済みのブログであっても適宜修正・追加することがあります。
We may make changes and additions to blogs already published.
posted by sakurai on October 10, 2023 #675

さらに前稿でインスタンスされるパイプラインFIFOであるFIFOL1のverilogライブラリのコードを見てみます。

assign FULL_N = !empty_reg || DEQ;
assign EMPTY_N = empty_reg ;

パイプラインFIFOは1段のF/Fなので、基本的にFULLとEMPTYは内部レジスタempty_regの背反ロジックとなりますが、例外的に下流からのDEQ要求がある場合は、仮にFULLであったとしても次のサイクルでFULLが解消されるため、DEQとのORをとり、not full(上位へのenq enable)とします。

always@(posedge CLK `BSV_ARESET_EDGE_META)
  begin
     if (RST == `BSV_RESET_VALUE)
        begin
          empty_reg <= `BSV_ASSIGNMENT_DELAY 1'b0;
        end
     else
        begin
           if (CLR)
             begin
                empty_reg <= `BSV_ASSIGNMENT_DELAY 1'b0;
             end
           else if (ENQ)
             begin
                empty_reg <= `BSV_ASSIGNMENT_DELAY 1'b1;
             end
           else if (DEQ)
             begin
                empty_reg <= `BSV_ASSIGNMENT_DELAY 1'b0;
              end // if (DEQ)
        end // else: !if(RST == `BSV_RESET_VALUE)
 end // always@ (posedge CLK or `BSV_RESET_EDGE RST)

empty_regはnot emptyを表す内部レジスタであり、ENQするとTrue(=1, not empty)となり、DEQするとFalse(=0, empty)となります。not fullは上位へのenq enable信号であり、not emptyは下位へのdeq enable信号です。当初なぜemptyもfullも負論理なのかと思いましたが、そういうことでした。

always@(posedge CLK `BSV_ARESET_EDGE_HEAD)
  begin
       begin
           if (ENQ)
             D_OUT     <= `BSV_ASSIGNMENT_DELAY D_IN;
        end // else: !if(RST == `BSV_RESET_VALUE)
  end // always@ (posedge CLK or `BSV_RESET_EDGE RST)

ENQはF/F入力の値を出力に移します。一方DEQはF/Fは何も変化させません。

これまで見たように、bscにより生成された回路を解析することは、論理設計能力の向上の一助となります。


左矢前のブログ 次のブログ右矢

posted by sakurai on October 9, 2023 #674

Maybeを使用した制御パイプラインをbscで合成し、生成されたverilogコードの一部を示します。

  // submodule ifs                                                                                                                        
  assign ifs$D_IN = { 1'd1, pc } ;
  assign ifs$ENQ = ifs$FULL_N ;
  assign ifs$DEQ = WILL_FIRE_RL_if_stage && !if_wait ;
  assign ifs$CLR = 1'b0 ;

  // rule RL_if_stage                                                                                                                     
  assign WILL_FIRE_RL_if_stage = ids$FULL_N && ifs$EMPTY_N ;

  // submodule ids                                                                                                                        
  assign ids$D_IN = { !if_wait && ifs$D_OUT[32], ifs$D_OUT[31:0] } ;
  assign ids$ENQ = WILL_FIRE_RL_if_stage ;
  assign ids$DEQ = WILL_FIRE_RL_id_stage  && !mc_wait ;
  assign ids$CLR = 1'b0 ;

  // rule RL_id_stage                                                                                                                     
  assign WILL_FIRE_RL_id_stage = exs$FULL_N && ids$EMPTY_N ;

図674.2はこのコードを回路図に変換したものです。ハードウエア設計者はHDLコードよりもstaticな回路図のほうが理解し易いです。

図%%.1
図674.1 制御パイプライン構造

各ステージ中のwait信号で上流方向は止めますが(中段左側のAND)、下流方向は止めずに(下段のAND)さらに下流にinvalidを流す(上段のAND)ところが、より単純な図673.1のデータパイプラインとの違いです。


左矢前のブログ 次のブログ右矢

posted by sakurai on October 6, 2023 #673

前回まではパイプラインのうち<IF>にwaitを入力しましたが、基本的に<WB>以外のステージにwaitが入る可能性があります。

表673.1 制御パイプラインウエイト制御
ステージ ウエイト信号 ウエイト原因 パイプライン処理
<PC> pc_wait PCの到着が遅れる場合。例えば分岐キャッシュから出力されるPCが遅れる場合。 上流へは同一サイクルでの停止とし、下流へはパイプラインバブルを流す。
<IF> if_wait 命令メモリから出力される命令データの到着が遅れる場合。例えばIキャッシュミスによるブロックインの場合。仮想記憶サポートの場合は、I-TLBミスによるページテーブルウォーク。 上流へは同一サイクルでの停止とし、下流へはパイプラインバブルを流す。
<ID> mc_wait 命令デコーダは1サイクル内で実行できるため、後続を待たせる必要が無いのでid_waitは無し。マルチサイクル命令の場合は内部的にパイプラインストリームを生成する処理。 上流へは同一サイクルでの停止とし、下流へはvalidな命令を内部的に複数生成し、パイプラインで流す。マルチサイクル(かつ複数パイプラインストリーム)動作なのでパイプラインバブルは流さない。
<EX> ex_wait 演算器から出力されるデータの到着が遅れる場合。複数サイクル演算が必要な例えば4サイクル乗算器のような演算。 上流へは同一サイクルでの停止とし、下流へはパイプラインバブルを流す。
<MA> ma_wait データメモリから出力されるデータデータの到着が遅れる場合。例えばDキャッシュミスによるブロックインの場合。仮想記憶サポートの場合は、D-TLBミスによるページテーブルウォーク。 上流へは同一サイクルでの停止とし、下流へはパイプラインバブルを流す。
<WB> --- WBは1サイクル内で実行でき、後続が無いのでwb_waitは無し。 ---

図673.1に各種wait信号を入力したデータパイプライン構造を示します。過去記事で調べた回路にwaitが追加されています。

図%%.1
図673.1 データパイプライン構造

図では信号名を3文字に短縮していますが、$\overline{\text{emp}}$は$\overline{\text{empty}}$の略でdeqのenable信号、$\overline{\text{ful}}$は$\overline{\text{full}}$の略で、enqのenable信号です。


左矢前のブログ 次のブログ右矢

posted by sakurai on October 5, 2023 #672

今回設計したFIFOは2段FIFOでした。従って、1つ前の記事のようにif_waitを2サイクルにすると、図672.1で示すとおり0034, 0038とPCが先に進みます。

図%%.1
図672.1 2wait入り2段PCパイプラインの波形

このようにパイプラインが次に進んでしまうということは、演算器等も2段分必要になります。従ってFIFOを1段に修正します。具体的にはmkFIFOmkLFIFOに変更します。

以下に修正箇所を示します。

Processor.bsv

FIFO#(int) ifs    <- mkLFIFO;
FIFO#(int) ids    <- mkLFIFO;
FIFO#(int) exs    <- mkLFIFO;
FIFO#(int) mas    <- mkLFIFO;
FIFO#(int) wbs    <- mkLFIFO;

以下はbsimシミュレーション波形です。図672.1ではif_waitによりPCが止まらずwait中に0038までも進んでしまいましたが、1段FIFO(パイプラインFIFO)に変更することで、if_waitが0030で入力されるとPCはその次のアドレスである0034で正しく止まっています。

図%%.2
図672.2 wait入り1段PCパイプラインの波形

図672.1, 図672.2共、Gtkwaveではtagのinvalidを自動認識しないため、パイプラインバブルのサイクルを手で赤で塗っています。


左矢前のブログ 次のブログ右矢

posted by sakurai on September 29, 2023 #671

パイプライン動作において、そのサイクルが有効か無効かは重要な情報です。無効サイクルはパイプラインバブルとも呼ばれます。

そこで、本来PCパイプラインには不要ですが、制御信号パイプラインに必要な、Maybe型を用いてパイプラインを記述します。Maybe型は以下に示すようにtagged unionで定義され、validの場合には値を持ちinvalidの場合には値を持たない型です。

typedef union tagged {
    void Invalid;
    data_t Valid;
} Maybe #(type data_t) deriving (Eq, Bits);

以下に修正箇所を示します。

Processor.bsv

int型のFIFOを設けていたところをMaybe型のFIFOに修正します。int型のペイロードに対して1bitのvalid/invalidを表すtagを付加します。

FIFO#(Maybe#(int)) ifs    <- mkFIFO;
FIFO#(Maybe#(int)) ids    <- mkFIFO;
FIFO#(Maybe#(int)) exs    <- mkFIFO;
FIFO#(Maybe#(int)) mas    <- mkFIFO;
FIFO#(Maybe#(int)) wbs    <- mkFIFO;

次に<IF>においてwaitが来たら上位のdeqと下位のenqを停止していましたが、制御信号の場合はwaitの時、下流にinvalidを流すように変更します。このinvalidはパイプラインバブルです。

     // <IF>
     rule if_stage;
        let pc_if = ifs.first;
        if (!if_wait) begin
           ifs.deq;                             // !waitの場合はデキュー
           $display (" pc_if = %04h", pc_if);
           ids.enq (pc_if);                 // !waitの場合はその値を下流にエンキュー
        end else begin
           ids.enq (tagged Invalid); // waitの場合下流にinvalidを流す
        end
     endrule

コンパイルと起動コマンドは以下のとおりです。

\$ bsc -u -sim Tb.bsv; bsc -sim -e mkTb -o mkTb.exe; ./mkTb.exe -V; gtkwave -A dump.vcd

以下はbsimシミュレーション波形です。Maybe型は33bitのデータでありMSBがvalid bitとなっています。 標準ではGtkwaveはMaybeのinvalidを認識せず赤色にならないため、手で赤色に修正しました。

図%%.1
図671.1 wait入りPCパイプラインの波形

以下はverilogシミュレーション波形です。verilogでも同様です。

図%%.2
図671.2 wait入りPCパイプラインの波形

bsimとverilogで全く同じ動作となっています。まとめとして、ステージ中にwaitが入る場合の処理は、

  • 上位へはdeqをサイクル中で停止、するとFIFOがfullでとまる。ただしFIFOは1段。
  • 下流へはデータパイプラインの場合はvalid bitは不要であり、値を保持
  • 下流へは制御パイプラインの場合はinvalid(パイプラインバブル)を流す

左矢前のブログ 次のブログ右矢

posted by sakurai on September 27, 2023 #669

次にパイプラインウェイトをテストします。具体的にはテストベンチにのwait信号を設け、途中でアサートします。

Tb.bsv

Tbにはその記述を追加します。

import StmtFSM::*;
import Processor::*;

(* synthesize *)
module mkTb();
    Empty proc <- mkProcessor();
    Stmt main = seq
         proc.if_wait_load(False);
         delay(10);
         proc.if_wait_load(True);
         delay(1);        // ここでif_waitを2サイクルアサート
         proc.if_wait_load(False);
         delay(10);
         $finish;
    endseq;
    mkAutoFSM(main);
endmodule

if_wait信号を1サイクルアサートをさせようとしてdelay(1);を挟みましたが、その前のload(True);により1サイクルアサートされるようです。そのため、1サイクルアサートさせるには以下の表のように、何も挟まないかdelay(0);と記述するようです。

表669.1 BSV構文とwaitアサート期間
BSV構文 waitアサート期間
proc.if_wait_load(True);
proc.if_wait_load(False);
1サイクル
proc.if_wait_load(True);
delay(0);
proc.if_wait_load(False);
1サイクル
proc.if_wait_load(True);
repeat(0) noAction;
proc.if_wait_load(False);
1サイクル
proc.if_wait_load(True);
noAction;
proc.if_wait_load(False);
2サイクル
proc.if_wait_load(True);
delay(1);
proc.if_wait_load(False);
2サイクル
proc.if_wait_load(True);
repeat(1) noAction;
proc.if_wait_load(False);
2サイクル

Processor.bsv

PCパイプラインにインタフェースを設け、そこにif_wait入力を設けます。

Import FIFO::*;

interface Processor_ifc;
    (* prefix="" *)
    method Action if_wait_load(Bool in_if_wait);
endinterface

(* synthesize, always_ready *)
module mkProcessor(Processor_ifc);

if_waitはレジスタで宣言します。

Reg#(Bool) if_wait <- mkReg(False);

<IF>において、waitが来たら上位のdeqと下位のenqを停止します。

     // <IF>
     rule if_stage;
         let pc_if = ifs.first;
         if (!if_wait) begin
             ifs.deq;
             $display (" pc_if = %04h", pc_if);
             ids.enq (pc_if);
         end
     endrule

コンパイルと起動コマンドは以下のとおりです。gtkwaveはここ

\$ bsc -u -sim Tb.bsv; bsc -sim -e mkTb -o mkTb.exe; ./mkTb.exe -V; gtkwave -A dump.vcd

以下はbsimシミュレーション波形です。if_waitを1サイクルアサートしようとして、delay(1);とすると2サイクルアサートされるので、1サイクルアサートするにはdelay(0);とするようです。

if_waitにより一旦はinvalidになりますが、そのデータを転送するとvalidになってしまうようです。

図%%.1
図669.1 wait入りPCパイプラインの波形(bsim)

以下はverilogシミュレーション波形です。if_waitによりinvalidになることはありません。

図%%.2
図669.2 wait入りPCパイプラインの波形(verilog)

左矢前のブログ 次のブログ右矢

posted by sakurai on September 26, 2023 #668

過去記事で設計したPCパイプラインをモジュールに変更し、その上にテストベンチをかぶせます。以下にテストベンチTb.bsv及びPCパイプラインProcessor.bsvのソースを示します。

Tb.bsv

import StmtFSM::*;
import Processor::*;

(* synthesize *)
module mkTb();
    Empty proc <- mkProcessor();
    Stmt main = seq
        delay(30);
        $finish;
    endseq;
    mkAutoFSM(main);
endmodule

Processor.bsv

import FIFO::*;

(* synthesize, always_ready *)
module mkProcessor(Empty);

    Reg#(int)  pc     <- mkReg(0);
    FIFO#(int) ifs    <- mkFIFO;
    FIFO#(int) ids    <- mkFIFO;
    FIFO#(int) exs    <- mkFIFO;
    FIFO#(int) mas    <- mkFIFO;
    FIFO#(int) wbs    <- mkFIFO;

     // <PC>
     rule pc_stage;
        if (pc > 100) $finish(0);
        $display("------");
        ifs.enq(pc);
        pc <= pc + 4;
     endrule

     // <IF>
     rule if_stage;
        let pc_if = ifs.first;
        ifs.deq;
        $display (" pc_if = %04h", pc_if);
        ids.enq (pc_if);
     endrule

     // <ID>
     rule id_stage;
        let pc_id = ids.first;
        ids.deq;
        $display (" pc_id = %04h", pc_id);
        exs.enq (pc_id);
     endrule

     // <EX>
     rule ex_stage;
        let pc_ex = exs.first;
        exs.deq;
        $display (" pc_ex = %04h", pc_ex);
        mas.enq (pc_ex);
     endrule

     // <MA>
     rule ma_stage;
        let pc_ma = mas.first;
        mas.deq;
        $display (" pc_ma = %04h", pc_ma);
        wbs.enq (pc_ma);
     endrule

     // <WB>
     rule wb_stage;
        let pc_wb = wbs.first;
        wbs.deq;
        $display (" pc_wb = %04h", pc_wb);
     endrule

endmodule: mkProcesso

コンパイルと起動コマンドは以下のとおりです。gtkwaveはここ

\$ bsc -u -sim Tb.bsv; bsc -sim -e mkTb -o mkTb.exe; ./mkTb.exe -V; gtkwave -A dump.vcd

図%%.1
図668.1 PCパイプラインの波形

左矢前のブログ 次のブログ右矢

Ultra96toPMODの追加製造費用

posted by sakurai on May 29, 2023 #608

Ulta96toPMOD基板製造再見積り

JLCPCBがPCBA(PCB製造及び部品実装)のセールをやっているようなので, 以前掲載したUltra96toPMODボードのオーダー費を再度計算してみました。

前回と同様パープルとグリーン基板を10枚製造し、さらにICを2個/枚×10枚実装した場合の費用の内訳を示します。前回パープル基板はEconomyの有利な価格で基板が製造できず、Standardとなっていました。今回はパープルもグリーンと同じEconomy扱いに変更されています。

表608.1 Ultra96toPMOD Jlcpcbの費用構成
10枚製造時費用内訳 基板色[USD]
グリーン パープル
PCB Special Offer Price 5.00
Components(TXS0108EPWR --- 20個) 9.39
Extended Components 2.96
SMT Assembly 0.65
Setup fee 7.88
Stencil 1.48
合計 27.36
送料(OCS Express:6~8日) 11.68
総計 39.04

前回と比較してみると、部品(レベコンIC)代が若干安くなり、セットアップフィー、SMTアセンブリ、ステンシルがほんの少し安くなりました。一方、送料が上がりクーポンが使えないので、40.2%の値上げ(パープルは28.6%の値下げ)という結果になりました。

今回、再度BokTech及びSeeedFusion PCBの見積もりを取りましたが、それぞれこの2倍、4倍ほどの費用となりました。JLCPCBの安さが光ります。

PMODピンソケットコネクタの再オーダー

PMOD仕様の12ピンソケットの型格はSamtec製のSSW-106-02-T-D-RAです。

図%%.1
図608.1 SSW-106-02-T-D-RA

以前オーダーしたときはMouser から購入しました。この時は単価が141円と安く送料が無料なこともあり、総額が安かったのですが、今回見積もったら単価が258円とかなり値上がりしていたため、Arrowから購入しました。

再度調べたところ、以下のように最安はChip 1stopでした。単価的にはArrowと同じですが、送料が無料となることから、今後はChip 1stopで購入しようと思います。

  • Chip1stop 単価156.2 x 40(送料650)= 6,899円 (税込み) 最安
  • Arrow 単価156.2 x 40(送料3,080)= 9,330円 (税込み)
  • RSオンライン 単価254.9x 40 (送料無料) =10,199円 (税込み)
  • Mouser 単価263.6 x 40 (送料無料) =10,542円 (税込み)

図%%.2
図608.2 送付部品(SSW-106-02-T-D-RA)

本ピンソケット互換品でA2541HWR-2x6Pという製品があるようです。


左矢前のブログ 次のブログ右矢

Ultra96toPMODのBOM

posted by sakurai on May 26, 2023 #607

Ultra96toPMODのBOM

弊社作成のUltra96toPMODボードですが、BoMを掲載していなかったので、掲載します。

表607.1 Ultra96toPMODボードBoM
Degignator Value Qty MPN
C1, C2, C4, ..., C11 0.1u 10 Multilayer Ceramic Capacitor
C3 10u 1 47 µF 50 V Aluminum Electrolytic Capacitors Radial
J1, ..., J4 SSW-106-02-T-D-RA 4 SSW-106-02-T-D-RA
J100 MTMM-120-03-T-D-155 1 MTMM-120-03-T-D-155
LED1 TLLR4400 1 Red LED 3mm Through Hole
R1 470 1 Axial Carbon Film Resistor
R2, ..., R4, R6 3.3k 4 Axial Carbon Film Resistor
R5 10k 1 Axial Carbon Film Resistor
SW1 COUNT 1 4bit DIP SW
SW2 RESET 1 Tactile Push SW
TP1, ..., TP10 Test Pin 10 Test Pin
U1, U3 TXS0108EPWR-TSSOP20 2 Level Converter IC (SMD)
U2 DC DC Converter IC 1 PQ3RD23

Online-shopの開設

併せてオンラインショップを開設しました。

図%%.1
図607.1 オンラインショップ画面

左矢前のブログ 次のブログ右矢

PL UARTの接続とPCでの表示

posted by sakurai on May 17, 2023 #605

PL部UARTのPCへの出力

以前Space Invadersのゲーム実行中のVRAM画面の吸出しを実施しました。過去記事ではこれ等が相当します。これは、メモリダンプモジュールをBSVにより設計し、UARTの送信機能を用いてUART/USB変換ボードを経由してPCとUSBで接続し、PC上のPuttyでメモリダンプ情報を取得するというものです。

ところが、再度実行しようとしたところ、どうしてもUARTの出力の取得ができませんでした。前回は比較的簡単にできてしまったので、記事にはpin設定であるxdcの詳細は書いていませんでした。単にUART_TXに接続するとのみと書いており、端子番号は今は定かではありません。

こうなると基本から調べなければならないので、まずUltra96V2の回路図を見ると、なんとPS部からの接続となっているようです。

図%%.1
図605.1 Ultra96 UART部分回路図

UART/USB変換ボードのJ1の2 pinにUART_TXが接続されていますが、これはPS_MIO0のUART1_TXであり、PLからはPIN配置でエラーになるため、PS部であるBank 500のU4端子に接続することはできません。図605.2にUltra96-V2ハードウェアユーザーズガイドの抜粋を示しますが、やはりBank 500(PS部)のU4端子となっています。

図%%.2
図605.2 Ultra96 UART部分端子表

従って、最後の手段としてボード上に配線をハンダ付けし無理やりJ1に出力することを考えます。

まず図605.3はPL部UART_TXの引き出しを示す回路図です。

図%%.3
図605.3 UART_TX部回路図

このUART_TXを次のxdcによりG6端子に割り当てます。これはPL部の出力(Bank 26)です。

set_property PACKAGE_PIN G6 [get_ports {UART_TX}]

最後にUART_TXを割り着けた端子G6とJ1の2 pinの間に配線をハンダ付けし、ショートしてやります。レベル的に本来はTrのD側ではなくS側に接続すべきですが、3.3Vにpull upされているため、これでもVOHは満足しているようです。

このようにすることで921,600bpsにより、VRAM内容の送信がうまく動作しました。が、以前設定だけでできた理由は不明のままです。

PCへの出力結果の確認

以下に、得られたlogファイルを画像に変換するフィルタを再掲します。

log2ppm.c

#include <stdio.h>
void main() {
      char line[4096];
      char ch;
      printf("P3\n256 256\n255\n");
      for(int y = 0; y <= 255; y++) {
            fgets(line, sizeof(line), stdin);
            for(int x = 0; x <= 255; x++) {
                  ch = line[x] - 0x30;
                  if ((ch & 0x4) != 0) printf("255 ");    // R
                  else printf("0 ");
                  if ((ch & 0x2) != 0) printf("255 ");    // G
                  else printf("0 ");
                  if ((ch & 0x1) != 0) printf("255 ");    // B
                  else printf("0 ");
            }
            printf("\n");
      }
}

以下のコマンドによりフィルタを作成します。

$ gcc -O log2ppm.c -o log2ppm

これを下記のようにフィルターとして実行し、ログデータを画像ファイルに変換します。

$ ./log2ppm <putty.log >putty.ppm

生成されたppm図形を図605.4に示します。

図%%.3
図605.4 メモリダンプ図形

左矢前のブログ 次のブログ右矢


ページ: