Google XLSでDDR3メモリコントローラーを設計してみる
背景
Googleがオープンソースで公開した高位合成処理系(半導体設計ソフトウェア)XLSをインストールしてみた。使い方を忘れないうちに実用回路を設計してみよう。
事前練習
xlsを使って、8bitカウンターを設計してみる
procを使ってみる。
(中略)
エラーとなり、進みません。
結論
過去の事前練習
xlsを使って、8bitカウンターを設計してみる
※(バイナリコードのxlsではなく、ソースからコンパイルしました。n100のPCでコンパイルに一晩以上かかりました。SSDの容量も100GB以上は必要です。)
コードはfnを使いました。procではどうやってもエラーとなり、verilogまで変換できない。
fn counter8(state: bits[8], rst_input: bits[1]) -> bits[8] {
// リセットが有効な場合、状態をリセット
if rst_input == bits[1]:1 {
bits[8]:0
} else {
// カウンタをインクリメント
state + bits[8]:1
}
}
Makefile一発で変換
# Variables
TOP = counter8
INPUT_FILE = counter8.x
IR_FILE = $(TOP).ir
OPT_IR_FILE = $(TOP)_opt.ir
OUTPUT_DIR = /home/haruhiko/xls/bazel-bin
OUTPUT_FILE = counter8.v
# Tools
INTERPRETER = $(OUTPUT_DIR)/xls/dslx/interpreter_main
IR_CONVERTER = $(OUTPUT_DIR)/xls/dslx/ir_convert/ir_converter_main
OPT_MAIN = $(OUTPUT_DIR)/xls/tools/opt_main
CODEGEN_MAIN = $(OUTPUT_DIR)/xls/tools/codegen_main
# Default target
all: codegen
# Targets with dependencies
ir_convert: interpret
$(IR_CONVERTER) --top=$(TOP) $(INPUT_FILE) > $(IR_FILE)
optimize: ir_convert
$(OPT_MAIN) $(IR_FILE) > $(OPT_IR_FILE)
codegen: optimize
$(CODEGEN_MAIN) \
--pipeline_stages=1 \
--delay_model=unit \
--module_name=counter8 \
$(OPT_IR_FILE) > $(OUTPUT_FILE)
interpret:
$(INTERPRETER) $(INPUT_FILE)
# Clean intermediate files
clean:
rm -f $(IR_FILE) $(OPT_IR_FILE) $(OUTPUT_FILE)
実行すると、、
haruhiko@haruhiko-Default-string:~/Program/GoogleXLS_test-main$ make
/home/haruhiko/xls/bazel-bin/xls/dslx/interpreter_main counter8.x
[===============] 0 test(s) ran; 0 failed; 0 skipped.
/home/haruhiko/xls/bazel-bin/xls/dslx/ir_convert/ir_converter_main --top=counter8 counter8.x > counter8.ir
/home/haruhiko/xls/bazel-bin/xls/tools/opt_main counter8.ir > counter8_opt.ir
/home/haruhiko/xls/bazel-bin/xls/tools/codegen_main \
--pipeline_stages=1 \
--delay_model=unit \
--module_name=counter8 \
counter8_opt.ir > counter8.v
haruhiko@haruhiko-Default-string:~/Program/GoogleXLS_test-main$
生成されたVerilogコードは、
module counter8(
input wire clk,
input wire [7:0] state,
input wire rst_input,
output wire [7:0] out
);
// ===== Pipe stage 0:
// Registers for pipe stage 0:
reg [7:0] p0_state;
reg p0_rst_input;
always_ff @ (posedge clk) begin
p0_state <= state;
p0_rst_input <= rst_input;
end
// ===== Pipe stage 1:
wire [7:0] p1_add_23_comb;
wire [7:0] p1_and_25_comb;
assign p1_add_23_comb = p0_state + 8'h01;
assign p1_and_25_comb = p1_add_23_comb & {8{~p0_rst_input}};
// Registers for pipe stage 1:
reg [7:0] p1_and_25;
always_ff @ (posedge clk) begin
p1_and_25 <= p1_and_25_comb;
end
assign out = p1_and_25;
endmodule
こうなりました。
人間並みのコードになりました。あ、まだまだダメですね。
procを使う必要があるようです。
次は実用回路を設計してみようか・・・
(今日は寝れそう・・)
過去の事前練習
xlsで、カウンターを設計してみる。
proc counter8 {
// 出力チャネル(カウンタ値出力)
count_out: chan<bits[8]> out;
// クロック入力チャネル
clk_in: chan<bits[1]> in;
// リセット入力チャネル
rst_in: chan<bits[1]> in;
// 初期状態としてカウンタを0で初期化
init { bits[8]:0 }
// configでプロセスのI/Oチャネルをバインドします
config(count_out: chan<bits[8]> out, clk_in: chan<bits[1]> in, rst_in: chan<bits[1]> in) {
(count_out, clk_in, rst_in)
}
// nextで状態更新ロジックを定義
next(state: bits[8]) {
// クロックとリセットの値を受信
let (tok_clk, clk_val) = recv(join(), clk_in);
let (tok_rst, rst_val) = recv(tok_clk, rst_in);
// リセットが有効なら次状態は0、そうでなければclkが1のときにカウントアップ
let next_state = if rst_val == bits[1]:1 {
bits[8]:0
} else {
if clk_val == bits[1]:1 {
state + bits[8]:1
} else {
state
}
};
// 次状態を出力チャネルに送信
let tok_out = send(tok_rst, count_out, next_state);
// 次状態を返すことで、次サイクルのstateとなる
next_state
}
}
実行すると
nishimura@nishimura-Default-string:~/Program$ interpreter_main counter8.x
[===============] 0 test(s) ran; 0 failed; 0 skipped.
→OK
verilogに変換
module __counter8__counter8_0_next(
input wire clk,
input wire rst_in,
input wire counter8__clk_in,
input wire counter8__clk_in_vld,
input wire counter8__rst_in,
input wire counter8__rst_in_vld,
input wire counter8__count_out_rdy,
output wire [7:0] counter8__count_out,
output wire counter8__count_out_vld,
output wire counter8__clk_in_rdy,
output wire counter8__rst_in_rdy
);
reg [7:0] ____state;
reg __counter8__clk_in_reg;
reg __counter8__clk_in_valid_reg;
reg __counter8__rst_in_reg;
reg __counter8__rst_in_valid_reg;
reg [7:0] __counter8__count_out_reg;
reg __counter8__count_out_valid_reg;
wire counter8__count_out_valid_inv;
wire p0_all_active_inputs_valid;
wire counter8__count_out_valid_load_en;
wire counter8__count_out_load_en;
wire p0_stage_done;
wire nor_94;
wire counter8__clk_in_valid_inv;
wire counter8__rst_in_valid_inv;
wire [7:0] add_85;
wire [1:0] concat_110;
wire counter8__clk_in_valid_load_en;
wire counter8__rst_in_valid_load_en;
wire [7:0] one_hot_sel_111;
wire and_118;
wire counter8__clk_in_load_en;
wire counter8__rst_in_load_en;
wire [7:0] next_state;
assign counter8__count_out_valid_inv = ~__counter8__count_out_valid_reg;
assign p0_all_active_inputs_valid = __counter8__clk_in_valid_reg & __counter8__rst_in_valid_reg;
assign counter8__count_out_valid_load_en = counter8__count_out_rdy | counter8__count_out_valid_inv;
assign counter8__count_out_load_en = p0_all_active_inputs_valid & counter8__count_out_valid_load_en;
assign p0_stage_done = p0_all_active_inputs_valid & counter8__count_out_load_en;
assign nor_94 = ~(__counter8__rst_in_reg | ~__counter8__clk_in_reg);
assign counter8__clk_in_valid_inv = ~__counter8__clk_in_valid_reg;
assign counter8__rst_in_valid_inv = ~__counter8__rst_in_valid_reg;
assign add_85 = ____state + 8'h01;
assign concat_110 = {__counter8__rst_in_reg & p0_stage_done, nor_94 & p0_stage_done};
assign counter8__clk_in_valid_load_en = p0_stage_done | counter8__clk_in_valid_inv;
assign counter8__rst_in_valid_load_en = p0_stage_done | counter8__rst_in_valid_inv;
assign one_hot_sel_111 = add_85 & {8{concat_110[0]}} | 8'h00 & {8{concat_110[1]}};
assign and_118 = (__counter8__rst_in_reg | nor_94) & p0_stage_done;
assign counter8__clk_in_load_en = counter8__clk_in_vld & counter8__clk_in_valid_load_en;
assign counter8__rst_in_load_en = counter8__rst_in_vld & counter8__rst_in_valid_load_en;
assign next_state = (__counter8__clk_in_reg ? add_85 : ____state) & {8{~__counter8__rst_in_reg}};
always_ff @ (posedge clk) begin
if (rst_in) begin
____state <= 8'h00;
__counter8__clk_in_reg <= 1'h0;
__counter8__clk_in_valid_reg <= 1'h0;
__counter8__rst_in_reg <= 1'h0;
__counter8__rst_in_valid_reg <= 1'h0;
__counter8__count_out_reg <= 8'h00;
__counter8__count_out_valid_reg <= 1'h0;
end else begin
____state <= and_118 ? one_hot_sel_111 : ____state;
__counter8__clk_in_reg <= counter8__clk_in_load_en ? counter8__clk_in : __counter8__clk_in_reg;
__counter8__clk_in_valid_reg <= counter8__clk_in_valid_load_en ? counter8__clk_in_vld : __counter8__clk_in_valid_reg;
__counter8__rst_in_reg <= counter8__rst_in_load_en ? counter8__rst_in : __counter8__rst_in_reg;
__counter8__rst_in_valid_reg <= counter8__rst_in_valid_load_en ? counter8__rst_in_vld : __counter8__rst_in_valid_reg;
__counter8__count_out_reg <= counter8__count_out_load_en ? next_state : __counter8__count_out_reg;
__counter8__count_out_valid_reg <= counter8__count_out_valid_load_en ? p0_all_active_inputs_valid : __counter8__count_out_valid_reg;
end
end
assign counter8__count_out = __counter8__count_out_reg;
assign counter8__count_out_vld = __counter8__count_out_valid_reg;
assign counter8__clk_in_rdy = counter8__clk_in_load_en;
assign counter8__rst_in_rdy = counter8__rst_in_load_en;
endmodule
これ。。
カウンターにはなってますが、
ここまで読みにくいVerilogコードが作成されてしまいます。
Settingがどこかにあるのでしょうが、
この設計ソフトを使うことにメリットあるのでしょうか?
最後
一旦、xlsで設計するのは止めます。
→conter8.xを数度、書き直しましたがダメでした。
これ以上は止めます。
組み合わせ回路の設計に使用するなら、メリットがあると思います。