Caravel template へのユーザ回路追加

本ドキュメントでは,サンプル回路の16-bitカウンタに AES の 8-bit S-Box のテーブルを追加し,ユーザ回路の追加からチップ作製データの作成やシミュレーションを行います.

注釈

なお,本ドキュメントでは,efabless 社 chipignite シャトルサービスを利用しました際のチップ作製データの生成手順を記述しています.チップ作製の詳細については,efabless 社へお問い合わせ下さい.

Caravel template 環境のディレクトリ構成

Caravel template 環境は下記のディレクトリ上に構築されているとします.

以下の項では,setenv.sh により環境設定がなされており,また,操作などは全て Caravel_mpw-9k/caravel_mpw-9k ディレクトリ上で実行することを想定しています.

$HOME/
|-- Caravel_mpw-9k/
    |-- caravel_mpw-9k/
    |-- dependencies/
    |   |-- openlane_src/
    |   |-- pdks/
    |-- precheck_mpw-9k/
    |setenv.sh

ユーザ回路のソースコードの修正・追加

Caravel template (Caravel_mpw-9k/caravel_mpw-9k) へユーザー回路を追加する際は,次のディレクトリへの操作を行います.

  • verilog/rtl,ユーザ回路のRTLファイルの追加・修正を行います.

  • openlane,ビルド対象のRTLファイルなどの設定を行います.

  • verilog/rtl/user_defines.v ファイルは環境構築時に修正されているとしています.

また,論理シミュレーションでは,別途,次のディレクトリへの操作を行います.

  • verilog/dv,シミュレーションのベクタなどの追加・修正を行います.

  • verilog/includes_folder,シミュレーション対象のRTLファイルを設定します.

注釈

RTLファイルの指定はビルドとシミュレーションで独立しており,シミュレーション結果と作製するチップ間で異なるRTLの組み合わせでない事に注意が必要です.

RTL ファイルの追加と修正

verilog/rtl のユーザ領域コードの修正や S-box テーブルの Verilog HDL ファイルを追加します.

ファイルの追加: AES_SBOX_ENC.v を verilog/rtl ディレクトリへ追加します.

AES_SBOX_ENC.v
//================================================ AES_SBOX_ENC
module AES_SBOX_ENC 
  (input  wire [7:0] x,
   output wire [7:0] y);

   //------------------------------------------------
   assign y = s(x[7:0]);

   function [7:0] s (input [7:0] x);
      case (x)
        8'h00: s=8'h63;  8'h01: s=8'h7c;  8'h02: s=8'h77;  8'h03: s=8'h7b;
        8'h04: s=8'hf2;  8'h05: s=8'h6b;  8'h06: s=8'h6f;  8'h07: s=8'hc5;
        8'h08: s=8'h30;  8'h09: s=8'h01;  8'h0A: s=8'h67;  8'h0B: s=8'h2b;
        8'h0C: s=8'hfe;  8'h0D: s=8'hd7;  8'h0E: s=8'hab;  8'h0F: s=8'h76;
        
        8'h10: s=8'hca;  8'h11: s=8'h82;  8'h12: s=8'hc9;  8'h13: s=8'h7d;
        8'h14: s=8'hfa;  8'h15: s=8'h59;  8'h16: s=8'h47;  8'h17: s=8'hf0;
        8'h18: s=8'had;  8'h19: s=8'hd4;  8'h1A: s=8'ha2;  8'h1B: s=8'haf;
        8'h1C: s=8'h9c;  8'h1D: s=8'ha4;  8'h1E: s=8'h72;  8'h1F: s=8'hc0;
        
        8'h20: s=8'hb7;  8'h21: s=8'hfd;  8'h22: s=8'h93;  8'h23: s=8'h26;
        8'h24: s=8'h36;  8'h25: s=8'h3f;  8'h26: s=8'hf7;  8'h27: s=8'hcc;
        8'h28: s=8'h34;  8'h29: s=8'ha5;  8'h2A: s=8'he5;  8'h2B: s=8'hf1;
        8'h2C: s=8'h71;  8'h2D: s=8'hd8;  8'h2E: s=8'h31;  8'h2F: s=8'h15;
        
        8'h30: s=8'h04;  8'h31: s=8'hc7;  8'h32: s=8'h23;  8'h33: s=8'hc3;
        8'h34: s=8'h18;  8'h35: s=8'h96;  8'h36: s=8'h05;  8'h37: s=8'h9a;
        8'h38: s=8'h07;  8'h39: s=8'h12;  8'h3A: s=8'h80;  8'h3B: s=8'he2;
        8'h3C: s=8'heb;  8'h3D: s=8'h27;  8'h3E: s=8'hb2;  8'h3F: s=8'h75;
        
        8'h40: s=8'h09;  8'h41: s=8'h83;  8'h42: s=8'h2c;  8'h43: s=8'h1a;
        8'h44: s=8'h1b;  8'h45: s=8'h6e;  8'h46: s=8'h5a;  8'h47: s=8'ha0;
        8'h48: s=8'h52;  8'h49: s=8'h3b;  8'h4A: s=8'hd6;  8'h4B: s=8'hb3;
        8'h4C: s=8'h29;  8'h4D: s=8'he3;  8'h4E: s=8'h2f;  8'h4F: s=8'h84;
        
        8'h50: s=8'h53;  8'h51: s=8'hd1;  8'h52: s=8'h00;  8'h53: s=8'hed;
        8'h54: s=8'h20;  8'h55: s=8'hfc;  8'h56: s=8'hb1;  8'h57: s=8'h5b;
        8'h58: s=8'h6a;  8'h59: s=8'hcb;  8'h5A: s=8'hbe;  8'h5B: s=8'h39;
        8'h5C: s=8'h4a;  8'h5D: s=8'h4c;  8'h5E: s=8'h58;  8'h5F: s=8'hcf;
        
        8'h60: s=8'hd0;  8'h61: s=8'hef;  8'h62: s=8'haa;  8'h63: s=8'hfb;
        8'h64: s=8'h43;  8'h65: s=8'h4d;  8'h66: s=8'h33;  8'h67: s=8'h85;
        8'h68: s=8'h45;  8'h69: s=8'hf9;  8'h6A: s=8'h02;  8'h6B: s=8'h7f;
        8'h6C: s=8'h50;  8'h6D: s=8'h3c;  8'h6E: s=8'h9f;  8'h6F: s=8'ha8;
        
        8'h70: s=8'h51;  8'h71: s=8'ha3;  8'h72: s=8'h40;  8'h73: s=8'h8f;
        8'h74: s=8'h92;  8'h75: s=8'h9d;  8'h76: s=8'h38;  8'h77: s=8'hf5;
        8'h78: s=8'hbc;  8'h79: s=8'hb6;  8'h7A: s=8'hda;  8'h7B: s=8'h21;
        8'h7C: s=8'h10;  8'h7D: s=8'hff;  8'h7E: s=8'hf3;  8'h7F: s=8'hd2;
        
        8'h80: s=8'hcd;  8'h81: s=8'h0c;  8'h82: s=8'h13;  8'h83: s=8'hec;
        8'h84: s=8'h5f;  8'h85: s=8'h97;  8'h86: s=8'h44;  8'h87: s=8'h17;
        8'h88: s=8'hc4;  8'h89: s=8'ha7;  8'h8A: s=8'h7e;  8'h8B: s=8'h3d;
        8'h8C: s=8'h64;  8'h8D: s=8'h5d;  8'h8E: s=8'h19;  8'h8F: s=8'h73;
        
        8'h90: s=8'h60;  8'h91: s=8'h81;  8'h92: s=8'h4f;  8'h93: s=8'hdc;
        8'h94: s=8'h22;  8'h95: s=8'h2a;  8'h96: s=8'h90;  8'h97: s=8'h88;
        8'h98: s=8'h46;  8'h99: s=8'hee;  8'h9A: s=8'hb8;  8'h9B: s=8'h14;
        8'h9C: s=8'hde;  8'h9D: s=8'h5e;  8'h9E: s=8'h0b;  8'h9F: s=8'hdb;
        
        8'hA0: s=8'he0;  8'hA1: s=8'h32;  8'hA2: s=8'h3a;  8'hA3: s=8'h0a;
        8'hA4: s=8'h49;  8'hA5: s=8'h06;  8'hA6: s=8'h24;  8'hA7: s=8'h5c;
        8'hA8: s=8'hc2;  8'hA9: s=8'hd3;  8'hAA: s=8'hac;  8'hAB: s=8'h62;
        8'hAC: s=8'h91;  8'hAD: s=8'h95;  8'hAE: s=8'he4;  8'hAF: s=8'h79;
        
        8'hB0: s=8'he7;  8'hB1: s=8'hc8;  8'hB2: s=8'h37;  8'hB3: s=8'h6d;
        8'hB4: s=8'h8d;  8'hB5: s=8'hd5;  8'hB6: s=8'h4e;  8'hB7: s=8'ha9;
        8'hB8: s=8'h6c;  8'hB9: s=8'h56;  8'hBA: s=8'hf4;  8'hBB: s=8'hea;
        8'hBC: s=8'h65;  8'hBD: s=8'h7a;  8'hBE: s=8'hae;  8'hBF: s=8'h08;
        
        8'hC0: s=8'hba;  8'hC1: s=8'h78;  8'hC2: s=8'h25;  8'hC3: s=8'h2e;
        8'hC4: s=8'h1c;  8'hC5: s=8'ha6;  8'hC6: s=8'hb4;  8'hC7: s=8'hc6;
        8'hC8: s=8'he8;  8'hC9: s=8'hdd;  8'hCA: s=8'h74;  8'hCB: s=8'h1f;
        8'hCC: s=8'h4b;  8'hCD: s=8'hbd;  8'hCE: s=8'h8b;  8'hCF: s=8'h8a;

        8'hD0: s=8'h70;  8'hD1: s=8'h3e;  8'hD2: s=8'hb5;  8'hD3: s=8'h66;
        8'hD4: s=8'h48;  8'hD5: s=8'h03;  8'hD6: s=8'hf6;  8'hD7: s=8'h0e;
        8'hD8: s=8'h61;  8'hD9: s=8'h35;  8'hDA: s=8'h57;  8'hDB: s=8'hb9;
        8'hDC: s=8'h86;  8'hDD: s=8'hc1;  8'hDE: s=8'h1d;  8'hDF: s=8'h9e;
        
        8'hE0: s=8'he1;  8'hE1: s=8'hf8;  8'hE2: s=8'h98;  8'hE3: s=8'h11;
        8'hE4: s=8'h69;  8'hE5: s=8'hd9;  8'hE6: s=8'h8e;  8'hE7: s=8'h94;
        8'hE8: s=8'h9b;  8'hE9: s=8'h1e;  8'hEA: s=8'h87;  8'hEB: s=8'he9;
        8'hEC: s=8'hce;  8'hED: s=8'h55;  8'hEE: s=8'h28;  8'hEF: s=8'hdf;
        
        8'hF0: s=8'h8c;  8'hF1: s=8'ha1;  8'hF2: s=8'h89;  8'hF3: s=8'h0d;
        8'hF4: s=8'hbf;  8'hF5: s=8'he6;  8'hF6: s=8'h42;  8'hF7: s=8'h68;
        8'hF8: s=8'h41;  8'hF9: s=8'h99;  8'hFA: s=8'h2d;  8'hFB: s=8'h0f;
        8'hFC: s=8'hb0;  8'hFD: s=8'h54;  8'hFE: s=8'hbb;  8'hFF: s=8'h16;
      endcase
   endfunction

endmodule // AES_SBOX_ENC

ユーザ領域コードの修正: verilog/rtl/

パッチファイルを利用して,ユーザ領域の回路本体 user_proj_example.v,制御回路との接続記述 user_project_wrapper.v を修正します.

user_proj_example.v では標準で 16-bit カウンタが実装されています.このカウンタの下位 8-bit を S-box モジュールへ入力し,8-bit の出力を得たのち,入出力の計 16-bit を出力するように修正します.また,Wishbone バスや内部ロジックアナライザの接続も同様に変更します.

$HOME/Caravel_mpw-9k ディレクトリに下記の内容の user_proj_example.v.patch を作成し,適用します.

user_proj_example.v.patch
76c76
<     wire [BITS-1:0] count;
---
>     wire [7:0] x, y;//    wire [BITS-1:0] count;
89c89
<     assign io_out = count;
---
>     assign io_out = {x, y};//    assign io_out = count;
96c96
<     assign la_data_out = {{(128-BITS){1'b0}}, count};
---
>     assign la_data_out = {{(128-BITS){1'b0}}, x, y};//    assign la_data_out = {{(128-BITS){1'b0}}, count};
115c115
<         .count(count)
---
>         .x(x), .y(y)//        .count(count)
132c132
<     output reg [BITS-1:0] count
---
>     output wire [7:0] x, y//    output reg [BITS-1:0] count
133a134
>     reg [BITS-1:0] count;
146c147
<                 rdata <= count;
---
>                 rdata <= {x, y};//                rdata <= count;
153a155,157
> 
>     assign x = count[7:0];
>     AES_SBOX_ENC sbox (.x(x), .y(y));

patch --dry-run caravel_mpw-9k/verilog/rtl/user_proj_example.v < user_proj_example.v.patch
patch caravel_mpw-9k/verilog/rtl/user_proj_example.v < user_proj_example.v.patch

user_project_wrapper.v では,ユーザ IO の出力を [37:30] [7:0] から [23:8] へ変更します.これは,ユーザ IO の先頭 8-bit が Caravel 制御回路の GPIO や SPI ROM,UART にも割り当てられており,チップの動作テストではこれら機能を利用するためです.

$HOME/Caravel_mpw-9k ディレクトリに下記の内容の user_project_wrapper.v.patch を作成し,適用します.

user_project_wrapper.v.patch
113,115c113,115
<     .io_in ({io_in[37:30],io_in[7:0]}),
<     .io_out({io_out[37:30],io_out[7:0]}),
<     .io_oeb({io_oeb[37:30],io_oeb[7:0]}),
---
>     .io_in (io_in[23:8]),
>     .io_out(io_out[23:8]),
>     .io_oeb(io_oeb[23:8]),

patch --dry-run caravel_mpw-9k/verilog/rtl/user_project_wrapper.v < user_project_wrapper.v.patch
patch caravel_mpw-9k/verilog/rtl/user_project_wrapper.v < user_project_wrapper.v.patch

ビルド設定ファイルの修正

user_proj_example のビルド時に AES_SBOX_ENC.v を含める設定を openlane/user_proj_example/config.json へ追加します.  verilog/rtl のユーザ領域コードの修正や S-box テーブルの Verilog HDL ファイルを追加します.

$HOME/Caravel_mpw-9k ディレクトリに下記の内容の config.json.patch を作成し,適用します.

config.json.patch
6c6,7
<         "dir::../../verilog/rtl/user_proj_example.v"
---
>         "dir::../../verilog/rtl/user_proj_example.v",
>         "dir::../../verilog/rtl/AES_SBOX_ENC.v"

patch --dry-run caravel_mpw-9k/openlane/user_proj_example/config.json < config.json.patch
patch caravel_mpw-9k/openlane/user_proj_example/config.json < config.json.patch

シミュレーション設定ファイルの修正

RTL シミュレーション実行時に AES_SBOX_ENC.v を含める設定を verilog/includes/includes.rtl.caravel_user_project へ追加します.

このほか,IO ポートのシミュレーション用ベクタ verilog/dv/io_ports/io_ports_tb.v のピン配置修正を行い,Caravel 制御 VexRiscv プロセッサの起動ファームウェアのコード verilog/dv/io_ports/io_ports.c を修正します.

$HOME/Caravel_mpw-9k ディレクトリに下記の内容の3つのファイルを作成します.

includes.rtl.caravel_user_project.patch
19c19
< 
---
> -v $(USER_PROJECT_VERILOG)/rtl/AES_SBOX_ENC.v

io_ports_tb.v.patch
29c29
< 	wire [7:0] mprj_io_0;
---
> 	wire [15:0] mprj_io_0;//	wire [7:0] mprj_io_0;
164,175c164,175
< 		wait(mprj_io_0 == 8'h01);
< 		wait(mprj_io_0 == 8'h02);
< 		wait(mprj_io_0 == 8'h03);
< 		wait(mprj_io_0 == 8'h04);
< 		wait(mprj_io_0 == 8'h05);
< 		wait(mprj_io_0 == 8'h06);
< 		wait(mprj_io_0 == 8'h07);
< 		wait(mprj_io_0 == 8'h08);
< 		wait(mprj_io_0 == 8'h09);
< 		wait(mprj_io_0 == 8'h0A);   
< 		wait(mprj_io_0 == 8'hFF);
< 		wait(mprj_io_0 == 8'h00);
---
> 		wait(mprj_io_0[15:8] == 8'h01);//		wait(mprj_io_0 == 8'h01);
> 		wait(mprj_io_0[15:8] == 8'h02);//		wait(mprj_io_0 == 8'h02);
> 		wait(mprj_io_0[15:8] == 8'h03);//		wait(mprj_io_0 == 8'h03);
> 		wait(mprj_io_0[15:8] == 8'h04);//		wait(mprj_io_0 == 8'h04);
> 		wait(mprj_io_0[15:8] == 8'h05);//		wait(mprj_io_0 == 8'h05);
> 		wait(mprj_io_0[15:8] == 8'h06);//		wait(mprj_io_0 == 8'h06);
> 		wait(mprj_io_0[15:8] == 8'h07);//		wait(mprj_io_0 == 8'h07);
> 		wait(mprj_io_0[15:8] == 8'h08);//		wait(mprj_io_0 == 8'h08);
> 		wait(mprj_io_0[15:8] == 8'h09);//		wait(mprj_io_0 == 8'h09);
> 		wait(mprj_io_0[15:8] == 8'h0A);//		wait(mprj_io_0 == 8'h0A);   
> 		wait(mprj_io_0[15:8] == 8'hFF);//		wait(mprj_io_0 == 8'hFF);
> 		wait(mprj_io_0[15:8] == 8'h00);//		wait(mprj_io_0 == 8'h00);

io_ports.c.patch
62,69c62,87
< 	reg_mprj_io_0 =  GPIO_MODE_USER_STD_OUTPUT;
< 	reg_mprj_io_1 =  GPIO_MODE_USER_STD_OUTPUT;
< 	reg_mprj_io_2 =  GPIO_MODE_USER_STD_OUTPUT;
< 	reg_mprj_io_3 =  GPIO_MODE_USER_STD_OUTPUT;
< 	reg_mprj_io_4 =  GPIO_MODE_USER_STD_OUTPUT;
< 	reg_mprj_io_5 =  GPIO_MODE_USER_STD_OUTPUT;
< 	reg_mprj_io_6 =  GPIO_MODE_USER_STD_OUTPUT;
< 	reg_mprj_io_7 =  GPIO_MODE_USER_STD_OUTPUT;
---
> 	//reg_mprj_io_0 =  GPIO_MODE_USER_STD_OUTPUT;
> 	//reg_mprj_io_1 =  GPIO_MODE_USER_STD_OUTPUT;
> 	//reg_mprj_io_2 =  GPIO_MODE_USER_STD_OUTPUT;
> 	//reg_mprj_io_3 =  GPIO_MODE_USER_STD_OUTPUT;
> 	//reg_mprj_io_4 =  GPIO_MODE_USER_STD_OUTPUT;
> 	//reg_mprj_io_5 =  GPIO_MODE_USER_STD_OUTPUT;
> 	//reg_mprj_io_6 =  GPIO_MODE_USER_STD_OUTPUT;
> 	//reg_mprj_io_7 =  GPIO_MODE_USER_STD_OUTPUT;
> 
> 	reg_mprj_io_8 =  GPIO_MODE_USER_STD_OUTPUT;
> 	reg_mprj_io_9 =  GPIO_MODE_USER_STD_OUTPUT;
> 	reg_mprj_io_10 =  GPIO_MODE_USER_STD_OUTPUT;
> 	reg_mprj_io_11 =  GPIO_MODE_USER_STD_OUTPUT;
> 	reg_mprj_io_12 =  GPIO_MODE_USER_STD_OUTPUT;
> 	reg_mprj_io_13 =  GPIO_MODE_USER_STD_OUTPUT;
> 	reg_mprj_io_14 =  GPIO_MODE_USER_STD_OUTPUT;
> 	reg_mprj_io_15 =  GPIO_MODE_USER_STD_OUTPUT;
> 
> 	reg_mprj_io_16 =  GPIO_MODE_USER_STD_OUTPUT;
> 	reg_mprj_io_17 =  GPIO_MODE_USER_STD_OUTPUT;
> 	reg_mprj_io_18 =  GPIO_MODE_USER_STD_OUTPUT;
> 	reg_mprj_io_19 =  GPIO_MODE_USER_STD_OUTPUT;
> 	reg_mprj_io_20 =  GPIO_MODE_USER_STD_OUTPUT;
> 	reg_mprj_io_21 =  GPIO_MODE_USER_STD_OUTPUT;
> 	reg_mprj_io_22 =  GPIO_MODE_USER_STD_OUTPUT;
> 	reg_mprj_io_23 =  GPIO_MODE_USER_STD_OUTPUT;

パッチのチェックを行います.

patch --dry-run caravel_mpw-9k/verilog/includes/includes.rtl.caravel_user_project < includes.rtl.caravel_user_project.patch
patch --dry-run caravel_mpw-9k/verilog/dv/io_ports/io_ports_tb.v < io_ports_tb.v.patch
patch --dry-run caravel_mpw-9k/verilog/dv/io_ports/io_ports.c < io_ports.c.patch

パッチを適用します.

patch caravel_mpw-9k/verilog/includes/includes.rtl.caravel_user_project < includes.rtl.caravel_user_project.patch
patch caravel_mpw-9k/verilog/dv/io_ports/io_ports_tb.v < io_ports_tb.v.patch
patch caravel_mpw-9k/verilog/dv/io_ports/io_ports.c < io_ports.c.patch

回路合成の実行

ユーザ回路の追加・修正やビルド・シミュレーション設定の修正後,ユーザ回路本体(user_proj_example)と Caravel へ接続するラッパー(user_project_wrapper)の合成を実行します.

make user_proj_example
make user_project_wrapper

エラーなど表示されず回路合成が成功すると「Flow complete」と表示され,gdsフォルダ下に user_progect_wrapper.gds ファイルが生成されます.

チップ作製データのチェック

回路合成により得られるチップ作製データの整合性などのチェックを行います. チェックではチップ製造の工程との整合性チェックのほか,説明ファイル README.md の内容についてもチェックされます.

README の修正

README.md を下記の例のように書き換えます.

This project is minimally modified to mpw-9k caravel template.
The function are a 16-bit counter and an S-box table. 16-bit IOs are set to OUTPUT.

チェックの実行

下記コマンドによりチェックを実行します. チェック中に不具合が見つかった場合でも全ての項目が確認され,1時間程度要します.

make run-precheck

全て項目のチェックに合格すると All Checks Passed !!! と表示されます.