「lpm_add_subを使っていれば問題無い」が結論なのですが、悔しいのでさらにチューニングしてみました。Fmaxを上げる事だけを考えているので実用的ではありません。手間暇かければ速くなるという例です。
回路の方針
32bitずつで加算を行い、各クロックでキャリーの計算を行いました。最後は速度が上がらなかったので、さらに16bitに分け計算を行っています。
always @ (posedge clk or negedge reset_x)begin if(reset_x == 0)begin c <= 0; tmp_a <= 0; tmp_b <= 0; tmp_c <= 0; tmp_d <= 0; carry32_a <= 0; carry64_ab <= 0; carry96_abc <= 0; carry_112_abcd <= 0; end else begin //stage a {carry32_a, tmp_a[31:0]} <= a[31:0] + b[31:0]; //stage b tmp_b[31:0] <= tmp_a[31:0]; {carry64_ab, tmp_b[63:32]} <= a[63:32] + b[63:32] + carry32_a; //statge c tmp_c[63:0] <= tmp_b[63:0]; {carry96_abc, tmp_c[95:64]} <= a[95:64] + b[95:64] + carry64_ab; //stage d tmp_d[95:0] <= tmp_c[95:0]; {carry_112_abcd, tmp_d[111:96]} <= a[111:96] + b[111:96] + carry96_abc; //stage e c[111:0] <= tmp_d[111:0]; c[128:112] <= a[127:112] + b[127:112] + carry_112_abcd; end end
全部で5stageに分けて加算を実行しています。この回路でなんとか300.12MHzを達成しました。どうやってもlpm_add_subを抜けなかった場合、加算器の記事全てが没になっていた可能性もあるのでほっとしています。パイプライン化が実装されていませんが、そちらは宿題として残しておきます。前後に依存関係がないので簡単に実装できるはずです。
クリティカルパスがこんな感じです。最適化オプションや配置をいじればもう少し速くなる余地はあります。今回はそういったオプションを使わないという条件ですのでここまでとします。