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 !!! と表示されます.