1問だけ解いた。
http://play.plaidctf.com/files/final_8ce2c1db4ce9e96bcc859ded79fba21c.sv
SystemVerilogのコード。最終的にwinが1となるような入力を求めよという問題。
実際にシミュレータで動かせれば楽だったけど、いくつかシミュレーターを試しても動かなかったので、手で解いた。
問題のコードを次のように直す。
- part_aからpart_dの中身を呼び出し元に展開
if (定数)
となるif分を削除- reset_Lを~resetにというように、単にassingされている変数を置き換えていく
- s_lとs_hはis_lの下位ビットと上位ビットなので、is_lに置き換え
- IMO1-IMO4を使った処理は、
assign im_f = user_in[is_i]
と等価
こうなる。
`default_nettype none module testbench; logic clock, win; logic [9:0] counter; logic [31:0] user_in; datapath d(.*); initial begin clock = 0; // Fill in the constant such that when the circuit hits cycle 360, // the logic "win" should be high. user_in = 32'b????????????????????????????????; reset = 1; #5 clock = ~clock; #5 clock = ~clock; #5 clock = ~clock; reset <= #1 0; for(counter = 0; counter < 70; counter++) begin #5 clock = ~clock; end end endmodule : testbench module datapath( input logic clock input logic [31:0] user_in, output logic win); logic [3:0] r1_out, r2_out; logic i_g_o, reset, init; logic init_delay; logic [7:0] is_i; always @(posedge clock) begin if (reset) is_i <= 0; else begin is_i <= ~init ? (is_i + 1) : is_i; end end always_ff @(posedge reg_en, posedge reset) begin if(~reset) begin r1_out <= r1_out + r2_out + init_delay; end else r1_out <= 0; end always_ff @(posedge ~reg_en, posedge reset) begin if(~reset) begin r2_out <= r1_out + r2_out + init_delay; end else r2_out <= 0; end always_ff @(posedge clock, posedge reset) begin if(~reset) begin i_g_o <= i_g_o | user_in[is_i]^{r2_out, r1_out}[is_i[2:0]; init <= 0; win <= win | (~(i_g_o | user_in[is_i]^{r2_out, r1_out}[is_i[2:0]) & (is_i == 8'b00011111)); init_delay <= init; end else i_g_o <= 0; init <= 1; win <= 0; init_delay <= 0; end assign reg_en = init | is_i[2]; endmodule: datapath
ハードウェアなので、上から順番に実行ではなく、 assign
で繋がれている所は代入元が変化したら代入先も常に変化する。 <=
の代入も上から順番ではなく、上の @
のところに書かれているタイミング(posedge x
は x
が0から1になった瞬間)に同時に起こる。
このプログラムが結局何をしているかというと、 reset
が1のときに初期化し、以降は clock
が変化する度に is_i
をカウントアップし、 user_in
の is_i
ビット目が {r2_out, r1_out}[is_i[2:0]]
に等しいかを調べている。 r1_out
と r2_out
は reg_en
が変化したタイミングで足しあわされる。
よって、次のPythonプログラムで、 user_in
に入れるべき値が分かる。
answer = [] r1_out = 0 r2_out = 0 reg_en_prev = 1 init_delay = 1 for i in range(32): answer += [(r2_out<<4|r1_out)>>(i&7)&1] a_out = r1_out + r2_out + init_delay init_delay = 0 reg_en = i>>2&1 if reg_en_prev==0 and reg_en==1: r1_out = a_out if reg_en_prev==1 and reg_en==0: r2_out = a_out reg_en_prev = reg_en print "".join(map(str, answer[::-1]))
01111100101110000001010000010000