module annealer_2x2( // 2x2のアニーリングマシン,外部磁場を考えないものとしての実装 input [3:0] init_spin, // 初期スピン input [3:0] interact0, interact1, interact2, interact3, interact4, interact5, // 相互作用係数,補数表現をする,7 ~ -8の値を取れる,4スピンなので6つ係数がある // [3:0]がビット幅 // interact0 <-- spin[0] to spin[1] // interact1 <-- spin[0] to spin[2] // interact2 <-- spin[0] to spin[3] // interact3 <-- spin[1] to spin[2] // interact4 <-- spin[1] to spin[3] // interact5 <-- spin[2] to spin[3] output [3:0] final_spin, // 解となるスピン input clk, reset_N, start, // クロック,リセット,演算開始,の信号 output busy // 演算中を表す信号 ); reg [3:0] spin; // スピンの値,今回は1, 0で表す(+1 --> 1, -1 --> 0) reg [3:0] J0, J1, J2, J3, J4, J5; // 相互作用係数 reg [6:0] H [4:0]; // ハミルトニアン(エネルギー),相互作用係数から42 ~ -42の値をとるので7ビット必要, // また,現在の状態 + ある1つのスピンの値が反転した場合の合計5通りの計算をしておく. reg state_init, state_busy, state_end; reg invert; // どのスピンを反転させるか wire [6:0] Jscale [5:0]; // Jを7ビットに拡張する,7ビットのwireが6本 wire [6:0] Sscale [3:0]; // スピンの値を7ビットに拡張する,スピンの値を符号ビットのように扱う. assign final_spin = spin; assign busy = state_busy; assign Jscale[0] = { { 4{J0[3]} }, J0[2:0] }; // 符号ビットを上位ビット側に4つ並べて拡張している assign Jscale[1] = { { 4{J1[3]} }, J1[2:0] }; assign Jscale[2] = { { 4{J2[3]} }, J2[2:0] }; assign Jscale[3] = { { 4{J3[3]} }, J3[2:0] }; assign Jscale[4] = { { 4{J4[3]} }, J4[2:0] }; assign Jscale[5] = { { 4{J5[3]} }, J5[2:0] }; assign Sscale[0] = { spin[0], 6'b000000 }; assign Sscale[1] = { spin[1], 6'b000000 }; assign Sscale[2] = { spin[2], 6'b000000 }; assign Sscale[3] = { spin[3], 6'b000000 }; always @( posedge clk or negedge reset_N ) begin if ( !reset_N ) { state_init, state_busy, state_end } <= 3'b100; if ( { state_init, state_busy, state_end } == 3'b100 ) begin spin <= init_spin; { J0, J1, J2, J3, J4, J5 } <= { interact0, interact1, interact2, interact3, interact4, interact5 }; if (start) { state_init, state_busy, state_end } <= 3'b010; end else if ( { state_init, state_busy, state_end } == 3'b010 ) begin H[0] <= ( Jscale[0] ^ Sscale[0] ^ Sscale[1] ^ 7'b1000000 ) + ( Jscale[1] ^ Sscale[0] ^ Sscale[2] ^ 7'b1000000 ) + ( Jscale[2] ^ Sscale[0] ^ Sscale[3] ^ 7'b1000000 ) + ( Jscale[3] ^ Sscale[1] ^ Sscale[2] ^ 7'b1000000 ) + ( Jscale[4] ^ Sscale[1] ^ Sscale[3] ^ 7'b1000000 ) + ( Jscale[5] ^ Sscale[2] ^ Sscale[3] ^ 7'b1000000 ); // ハミルトニアンの計算,シグマの前の符号は各項に分配している(7'b1000000でXORを取ることで符号を反転させている) H[1] <= ( Jscale[0] ^ Sscale[0] ^ Sscale[1] ) + ( Jscale[1] ^ Sscale[0] ^ Sscale[2] ) + ( Jscale[2] ^ Sscale[0] ^ Sscale[3] ) + ( Jscale[3] ^ Sscale[1] ^ Sscale[2] ^ 7'b1000000 ) + ( Jscale[4] ^ Sscale[1] ^ Sscale[3] ^ 7'b1000000 ) + ( Jscale[5] ^ Sscale[2] ^ Sscale[3] ^ 7'b1000000 ); // spin[0]が反転した時を想定したハミルトニアンの計算, // spin[0]が使われている(Sscale[0]を含む)項の符号を反転させなければ良い H[2] <= ( Jscale[0] ^ Sscale[0] ^ Sscale[1] ) + ( Jscale[1] ^ Sscale[0] ^ Sscale[2] ^ 7'b1000000 ) + ( Jscale[2] ^ Sscale[0] ^ Sscale[3] ^ 7'b1000000 ) + ( Jscale[3] ^ Sscale[1] ^ Sscale[2] ) + ( Jscale[4] ^ Sscale[1] ^ Sscale[3] ) + ( Jscale[5] ^ Sscale[2] ^ Sscale[3] ^ 7'b1000000 ); // spin[1]の反転 H[3] <= ( Jscale[0] ^ Sscale[0] ^ Sscale[1] ^ 7'b1000000 ) + ( Jscale[1] ^ Sscale[0] ^ Sscale[2] ) + ( Jscale[2] ^ Sscale[0] ^ Sscale[3] ^ 7'b1000000 ) + ( Jscale[3] ^ Sscale[1] ^ Sscale[2] ) + ( Jscale[4] ^ Sscale[1] ^ Sscale[3] ^ 7'b1000000 ) + ( Jscale[5] ^ Sscale[2] ^ Sscale[3] ); // spin[2]の反転 H[3] <= ( Jscale[0] ^ Sscale[0] ^ Sscale[1] ^ 7'b1000000 ) + ( Jscale[1] ^ Sscale[0] ^ Sscale[2] ^ 7'b1000000 ) + ( Jscale[2] ^ Sscale[0] ^ Sscale[3] ) + ( Jscale[3] ^ Sscale[1] ^ Sscale[2] ^ 7'b1000000 ) + ( Jscale[4] ^ Sscale[1] ^ Sscale[3] ) + ( Jscale[5] ^ Sscale[2] ^ Sscale[3] ); // spin[3]の反転 // ハミルトニアンが最小となる反転を見つける. if( $signed(H[1]) < $signed(H[2]) ) // Hはunsignedなので,キャストしてから比較 if( $signed(H[1]) < $signed(H[3]) ) if( $signed(H[1]) < $signed(H[4]) ) invert <= 1; else invert <= 4; else if ( $signed(H[3]) < $signed(H[4]) ) invert <= 3; else invert <= 4; else if ( $signed(H[2]) < $signed(H[3]) ) if ( $signed(H[2]) < $signed(H[4]) ) invert <= 2; else invert <= 4; else if ( $signed(H[3]) < $signed(H[4]) ) invert <= 3; else invert <= 4; if ( $signed(H[invert]) < $signed(H[0]) ) // 反転させた方がエネルギーが小さくなった場合 spin[invert] <= ~spin[invert]; else {state_init, state_busy, state_end} <= 3'b001; end else if ({state_init, state_busy, state_end} == 3'b001) begin {state_init, state_busy, state_end} <= 3'b001; end else begin {state_init, state_busy, state_end} <= 3'b100; end end endmodule