Last active
June 9, 2021 15:08
-
-
Save yuichiro-shibata/80689033fae964ecfd68e99a0a2dc3e8 to your computer and use it in GitHub Desktop.
ACRi ブログ「DA コンバータがなくてもできる FPGA ピアノ (5)」のコード
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
`default_nettype none | |
module autoplayer | |
#( | |
parameter real CLK_FREQ = 100e6, // クロック周波数 (Hz) | |
parameter real MM = 140 // メトロノームテンポ | |
) | |
( | |
input wire clk, | |
input wire ctrl_in, // 制御ボタン入力 | |
output logic [47:0] en_out | |
); | |
localparam int N_COUNTS = $ceil(CLK_FREQ * 60.0 / MM / 4.0); // 16分音符を基準 | |
localparam int N_TACTS = 880; // データの行数 | |
logic is_playing = 1'b0; // 演奏状態レジスタ | |
logic ctrl_pressed; // 制御ボタン入力イベントフラグ | |
logic ctrl_in_prev = 1'b0; // 1クロック前の制御ボタン | |
logic [$clog2(N_COUNTS)-1:0] count = '0; // テンポ制御用カウンタ | |
logic [$clog2(N_TACTS)-1:0] addr; // アドレスカウンタ | |
// 制御ボタン入力の立ち上がりエッジ検出 | |
always @(posedge clk) begin | |
ctrl_in_prev <= ctrl_in; | |
end | |
assign ctrl_pressed = ctrl_in & (!ctrl_in_prev); | |
// 演奏開始・停止の状態制御 | |
always @(posedge clk) begin | |
if (!is_playing && ctrl_pressed) | |
is_playing <= 1'b1; | |
else if (is_playing && addr == (N_TACTS-1) && count == (N_COUNTS-1)) | |
is_playing <= 1'b0; | |
else if (is_playing && ctrl_pressed) | |
is_playing <= 1'b0; | |
end | |
// 設定されたテンポで1拍をカウント | |
always @(posedge clk) begin | |
if (count == (N_COUNTS-1)) | |
count <= '0; | |
else | |
count <= count + 1'b1; | |
end | |
// アドレスのインクリメント | |
always @(posedge clk) begin | |
if (!is_playing) | |
addr <= '0; | |
else if (count == (N_COUNTS-1)) begin | |
if (addr == (N_TACTS-1)) | |
addr <= '0; | |
else | |
addr <= addr + 1'b1; | |
end | |
end | |
// ROM を BRAM として推論させファイルで初期化 | |
(* rom_style = "block" *) logic [47:0] play_mem[N_TACTS]; | |
initial $readmemh("eknm.mem", play_mem); | |
// ROM の読み出し | |
logic [47:0] play_mem_out; | |
always @(posedge clk) begin | |
play_mem_out <= play_mem[addr]; | |
end | |
// 読み出したイネーブル情報を出力 | |
assign en_out = is_playing? play_mem_out: '0; | |
endmodule | |
`default_nettype wire |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
`default_nettype none | |
module delta_sigma | |
#( | |
parameter int WIDTH = 16 | |
) | |
( | |
input wire clk, | |
input wire [WIDTH-1:0] data_in, | |
output logic pulse_out | |
); | |
logic [(WIDTH+1)-1:0] sigma_reg = '1; // シグマレジスタ | |
always @(posedge clk) begin | |
sigma_reg <= sigma_reg + {pulse_out, data_in}; // デルタ加算とシグマ加算 | |
end | |
assign pulse_out = ~sigma_reg[(WIDTH+1)-1]; // 2値化 | |
endmodule | |
`default_nettype wire |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
001011081000 | |
001011081000 | |
001011081000 | |
001011081000 | |
000000000000 | |
000000000000 | |
000080080080 | |
000080080080 | |
001001001000 | |
001001001000 | |
001001001000 | |
001001001000 | |
000000000000 | |
000000000000 | |
000080080080 | |
000080080080 | |
001001001000 | |
001001001000 | |
000080080080 | |
000080080080 | |
001001001000 | |
001001001000 | |
010010010000 | |
010010010000 | |
080080080000 | |
080080080000 | |
080080080000 | |
080080080000 | |
000000000000 | |
000000000000 | |
000000000000 | |
000000000000 | |
020020020000 | |
020020020000 | |
020020020000 | |
020020020000 | |
000000000000 | |
000000000000 | |
004004004000 | |
004004004000 | |
020020020000 | |
020020020000 | |
020020020000 | |
020020020000 | |
000000000000 | |
000000000000 | |
004004004000 | |
004004004000 | |
020020020000 | |
020020020000 | |
004004004000 | |
004004004000 | |
000800800800 | |
000800800800 | |
004004004000 | |
004004004000 | |
000080080080 | |
000080080080 | |
000080080080 | |
000080080080 | |
000000000000 | |
000000000000 | |
000000000000 | |
000000000000 | |
001011011000 | |
001000080000 | |
000001011000 | |
000000080000 | |
001001011000 | |
001000080000 | |
001001011000 | |
001000080000 | |
001001011000 | |
001000080000 | |
010001011000 | |
010000080000 | |
004001011000 | |
000000080000 | |
001001011000 | |
000000080000 | |
004004021000 | |
001000080000 | |
000804021000 | |
000000080000 | |
000804021000 | |
000800080000 | |
000804021000 | |
000800080000 | |
000804021000 | |
000804080000 | |
004020021000 | |
004000080000 | |
020000821000 | |
000000880000 | |
000804021000 | |
000000080000 | |
004001011000 | |
004000080000 | |
001001011000 | |
000000080000 | |
001001011000 | |
001000080000 | |
001001011000 | |
001000080000 | |
001001011000 | |
001000080000 | |
010001011000 | |
010000080000 | |
004001011000 | |
000000080000 | |
001001011000 | |
000000080000 | |
004004021000 | |
001000080000 | |
000804021000 | |
000000080000 | |
000804021000 | |
000800080000 | |
000804021000 | |
000800080000 | |
000804021000 | |
000804080000 | |
004020021000 | |
004000080000 | |
020000821000 | |
000000880000 | |
000804021000 | |
000000080000 | |
001000091000 | |
000000080000 | |
001000081000 | |
000000080000 | |
001020084000 | |
000800080000 | |
000220084000 | |
000800080000 | |
001080090000 | |
000000080000 | |
001080090000 | |
000000080000 | |
010020080800 | |
004020080000 | |
001010080800 | |
004004080000 | |
010001081000 | |
000000080000 | |
010001081000 | |
000000080000 | |
080000884000 | |
020000080000 | |
010000884000 | |
020000080000 | |
080001090000 | |
080001090000 | |
080001090000 | |
080001090000 | |
000000000000 | |
000000000000 | |
000000000000 | |
000000000000 | |
000090000000 | |
000090000000 | |
000090000000 | |
000090000000 | |
000090000000 | |
000090000000 | |
000090000000 | |
000090000000 | |
000220000000 | |
000220000000 | |
000220000000 | |
000220000000 | |
000220000000 | |
000220000000 | |
000220000000 | |
000220000000 | |
000090000880 | |
000024000880 | |
000024000880 | |
000000000880 | |
000024000880 | |
000024000880 | |
000024000880 | |
000000000880 | |
000024001200 | |
000011001200 | |
000011001200 | |
000000001200 | |
000011001200 | |
000011001200 | |
000011001200 | |
000000001200 | |
000010220020 | |
000004220020 | |
000004220020 | |
000000000000 | |
000004220020 | |
000004220020 | |
000004220020 | |
000000000000 | |
000001024080 | |
000001024080 | |
000000824080 | |
000000024000 | |
000000204080 | |
000000004080 | |
000000804080 | |
000000004080 | |
000001080090 | |
000001080090 | |
000000000000 | |
000000000000 | |
000004880080 | |
000004880080 | |
000000000000 | |
000000000000 | |
000011081000 | |
000011081000 | |
000000081000 | |
000000081000 | |
000000000000 | |
000000000000 | |
000000000000 | |
000000000000 | |
000090000000 | |
000090000000 | |
000090000000 | |
000090000000 | |
000090000000 | |
000090000000 | |
000090000000 | |
000090000000 | |
000220000000 | |
000220000000 | |
000220000000 | |
000220000000 | |
000220000000 | |
000220000000 | |
000220000000 | |
000220000000 | |
000090800080 | |
000090800080 | |
000024800080 | |
000000800080 | |
000024800080 | |
000000800080 | |
000024800080 | |
000000800080 | |
000025000200 | |
000025000200 | |
000011000200 | |
000001000200 | |
000011000200 | |
000001000200 | |
000011000200 | |
000001000200 | |
000010220020 | |
000010220020 | |
000004220020 | |
000000000000 | |
000004220020 | |
000000000020 | |
000004220020 | |
000000000000 | |
000001024080 | |
000001024080 | |
000000824080 | |
000000800000 | |
000000224080 | |
000000200080 | |
000000824080 | |
000000800000 | |
000001011000 | |
000001010000 | |
000001011000 | |
000001010000 | |
000001011000 | |
000001010000 | |
000001011000 | |
000001010000 | |
000001011000 | |
000000000000 | |
000001011000 | |
000001814000 | |
000004021000 | |
000004020000 | |
000000805000 | |
000000804000 | |
000011001000 | |
000011000000 | |
000011001000 | |
000011000000 | |
000011001000 | |
000011000000 | |
000011001000 | |
000011000000 | |
000011001000 | |
000011000000 | |
000004801000 | |
000011000000 | |
000024001000 | |
000024000000 | |
000004801000 | |
000004800000 | |
000090001000 | |
000090000000 | |
000091001000 | |
000090000000 | |
000091001000 | |
000090000000 | |
000091001000 | |
000090000000 | |
000221001000 | |
000220000000 | |
000221001000 | |
000220000000 | |
000824001000 | |
000820000000 | |
000824001000 | |
000820000000 | |
001011001000 | |
001010000000 | |
001011001000 | |
001010000000 | |
004080800800 | |
004080000000 | |
004080800800 | |
004080000000 | |
010081001000 | |
010080000000 | |
010081001000 | |
010080000000 | |
041000200200 | |
041000000000 | |
041000200200 | |
041000000000 | |
080800080080 | |
080804000000 | |
080800080080 | |
080804000000 | |
080800080080 | |
080804000000 | |
004800080080 | |
004804000000 | |
041000200080 | |
041004000000 | |
041000200080 | |
005004000000 | |
041000200080 | |
041004000000 | |
041000200080 | |
005004000000 | |
080800080080 | |
080804000000 | |
080800080080 | |
080804000000 | |
080800080080 | |
080804000000 | |
004800080080 | |
004804000000 | |
041000200080 | |
041004000000 | |
041000200080 | |
005004000000 | |
041000200080 | |
041004000000 | |
041000200080 | |
005004000000 | |
080880800080 | |
000000800080 | |
080881000200 | |
080881000200 | |
080884000800 | |
000004000800 | |
080881000200 | |
080881000200 | |
080880800080 | |
000000800080 | |
080881000200 | |
080881000200 | |
080884000800 | |
000004000800 | |
080880800080 | |
080880800080 | |
080290001000 | |
000010001000 | |
080284004000 | |
080284004000 | |
080281010000 | |
000001010000 | |
080284004000 | |
080284004000 | |
080290001000 | |
000010001000 | |
080284004000 | |
080284004000 | |
080282010000 | |
000002010000 | |
080290002000 | |
080290002000 | |
040044004000 | |
040200000000 | |
004044004000 | |
004200000000 | |
080084004000 | |
080800000000 | |
004084004000 | |
004800000000 | |
040044004000 | |
040200000000 | |
004044004000 | |
004200000000 | |
080084004000 | |
080800000000 | |
004084004000 | |
004800000000 | |
040244004000 | |
040240000000 | |
000004004004 | |
000000000000 | |
000004004004 | |
000000000000 | |
000004004004 | |
000000000000 | |
000004004004 | |
000004004004 | |
000004004004 | |
000004004004 | |
000000000000 | |
000000000000 | |
000000000000 | |
000000000000 | |
004004000000 | |
004004000000 | |
004004000000 | |
004004000000 | |
004004000000 | |
001001000000 | |
000800800000 | |
000200200000 | |
000080080000 | |
000080080000 | |
000000000000 | |
000000000000 | |
010010800100 | |
010010800100 | |
000000000000 | |
000000000000 | |
001001010200 | |
001001010200 | |
000000000000 | |
000000000000 | |
000201200080 | |
000201200080 | |
000000000000 | |
000000000000 | |
004004200040 | |
004004200040 | |
000000000000 | |
000000000000 | |
000000040004 | |
000000040004 | |
000000000000 | |
000000000000 | |
000800800000 | |
000800800000 | |
000800800000 | |
000800800000 | |
000800a00008 | |
000200200008 | |
000080280008 | |
000040240008 | |
000010090010 | |
000010090010 | |
000000000000 | |
000000000000 | |
001001200001 | |
001001200001 | |
000000000000 | |
000000000000 | |
000800880004 | |
000800880004 | |
000800880004 | |
000800880004 | |
000800884000 | |
000800884000 | |
000800884000 | |
000800884000 | |
000200244000 | |
000200244000 | |
000200242000 | |
000200242000 | |
000000001000 | |
000000001000 | |
000000000200 | |
000000000200 | |
000004000080 | |
000004000080 | |
004004000000 | |
000004000000 | |
004004040200 | |
000001040200 | |
004000840000 | |
000000240000 | |
004000080800 | |
000000080800 | |
004000000000 | |
000000000000 | |
004010800100 | |
000010800100 | |
004000000000 | |
000000000000 | |
004001010200 | |
000001010200 | |
004000000000 | |
000000000000 | |
004000201080 | |
000000201080 | |
004000000000 | |
000000000000 | |
004004000240 | |
000004000240 | |
004004000200 | |
000004000200 | |
010000000004 | |
000000000004 | |
040001200000 | |
000000000000 | |
040001200010 | |
040001200010 | |
080000880000 | |
080000880000 | |
000000001000 | |
000000001000 | |
011000000000 | |
000000000000 | |
011000004000 | |
011000004000 | |
004800000000 | |
004800000000 | |
000000000004 | |
000000000004 | |
000041000000 | |
000041000000 | |
000080880080 | |
000080000080 | |
000080880080 | |
000080000080 | |
000001200000 | |
000000000000 | |
004001200000 | |
000000000000 | |
080004800000 | |
080000000000 | |
040004800000 | |
040000000000 | |
010000880000 | |
010000000000 | |
004000880000 | |
004000000000 | |
010000240004 | |
010000000004 | |
004000240004 | |
004000000004 | |
000000880000 | |
000000000000 | |
004000880000 | |
000000000000 | |
004001200000 | |
000000000000 | |
004001200000 | |
000000000000 | |
004000240000 | |
000000000000 | |
004000240000 | |
000000000000 | |
010000880080 | |
010000000080 | |
004000880080 | |
004000000080 | |
000001200000 | |
000000000000 | |
004001200000 | |
000000000000 | |
080004800000 | |
080000000000 | |
040004800000 | |
040000000000 | |
010000880000 | |
010000000000 | |
004000880000 | |
004000000000 | |
010000240004 | |
010000000004 | |
004000240004 | |
004000000004 | |
000000880000 | |
000000000000 | |
004000880000 | |
000000000000 | |
004001200000 | |
000000000000 | |
004001200000 | |
000000000000 | |
004000240000 | |
000000000000 | |
004000240000 | |
000000000000 | |
010000880000 | |
010000800000 | |
004000880080 | |
004000880080 | |
000000800800 | |
000000800800 | |
000000200200 | |
000000200200 | |
010810100100 | |
010810100100 | |
010810010010 | |
010810010010 | |
010810040040 | |
004810040040 | |
001810100100 | |
000810100100 | |
001200200200 | |
001200200200 | |
001201001000 | |
001201001000 | |
000000200200 | |
000000200200 | |
000000080080 | |
000000080080 | |
004204040040 | |
004204040040 | |
004204004004 | |
004204004004 | |
004204010010 | |
001204010010 | |
000a04040040 | |
000204040040 | |
000880080080 | |
000800000000 | |
000880000080 | |
000800000080 | |
001080000200 | |
000000000200 | |
004080000800 | |
000000000800 | |
011080001000 | |
011000000000 | |
044080001000 | |
090000000000 | |
044080001000 | |
000000000000 | |
011080001000 | |
000000000000 | |
011080004000 | |
011080000000 | |
004804004000 | |
000000000000 | |
000884004000 | |
000000000000 | |
004804004000 | |
000000000000 | |
004804000004 | |
004800000000 | |
001204000004 | |
000000000000 | |
000884000004 | |
000000000000 | |
000241000004 | |
000000000000 | |
000080800080 | |
000080000080 | |
000080880080 | |
000080000080 | |
000001200000 | |
000000000000 | |
004001200000 | |
000000000000 | |
080004800000 | |
080000000000 | |
040004800000 | |
040000000000 | |
010000880000 | |
010000000000 | |
004000880000 | |
004000000000 | |
040000240004 | |
010000000004 | |
004000240004 | |
004000000004 | |
000000880000 | |
000000000000 | |
004000880000 | |
000000000000 | |
004001200000 | |
000000000000 | |
004001200000 | |
000000000000 | |
004000240000 | |
000000000000 | |
004000240000 | |
000000000000 | |
040000880080 | |
010000000080 | |
004000880080 | |
004000000080 | |
000001200000 | |
000000000000 | |
004001200000 | |
000000000000 | |
080004800000 | |
080000000000 | |
040004800000 | |
040000000000 | |
010000880000 | |
010000000000 | |
004000880000 | |
004000000000 | |
040000240004 | |
010000000004 | |
004000240004 | |
004000000004 | |
000000880000 | |
000000000000 | |
004000880000 | |
000000000000 | |
004001200000 | |
000000000000 | |
004001200000 | |
000000000000 | |
004000240000 | |
000000000000 | |
004000240000 | |
000000000000 | |
040000880000 | |
010000800000 | |
004000880080 | |
004000880080 | |
000000800800 | |
000000800800 | |
000000200200 | |
000000200200 | |
010810100100 | |
010810100100 | |
010810010010 | |
010810010010 | |
010810040040 | |
004810040040 | |
001810100100 | |
000810100100 | |
001200200200 | |
001200200200 | |
001201001000 | |
001201001000 | |
000000200200 | |
000000200200 | |
000000080080 | |
000000080080 | |
004204040040 | |
004204040040 | |
004204004004 | |
004204004004 | |
004204010010 | |
001204010010 | |
000a04040040 | |
000204040040 | |
000880080080 | |
000800000000 | |
000880000080 | |
000800000080 | |
001080000200 | |
000000000200 | |
004080000800 | |
000000000800 | |
011080001000 | |
011000000000 | |
044080001000 | |
090000000000 | |
044080001000 | |
000000000000 | |
011080001000 | |
000000000000 | |
011080004000 | |
011080000000 | |
004804004000 | |
000000000000 | |
000884004000 | |
000000000000 | |
004804004000 | |
000000000000 | |
004804000004 | |
004800000000 | |
001204000004 | |
000000000000 | |
000884000004 | |
000000000000 | |
000241000004 | |
000000000000 | |
000080800080 | |
000080000000 | |
000004004004 | |
000004004004 | |
000010010010 | |
000010010010 | |
000040040040 | |
000040040040 | |
000080080080 | |
000000000000 | |
000080080080 | |
000080000000 | |
000800200200 | |
000200000000 | |
000080200200 | |
000200000000 | |
000800800800 | |
000800800800 | |
000040040040 | |
000040040040 | |
000080080080 | |
000080080080 | |
000200200200 | |
000200200200 | |
000800800800 | |
000000000000 | |
000800800800 | |
000800000000 | |
004001001000 | |
001000000000 | |
000801001000 | |
001000000000 | |
004004004000 | |
000000000000 | |
004004004000 | |
004000000000 | |
010008008000 | |
008000000000 | |
002008008000 | |
008000000000 | |
010010010000 | |
010010010000 | |
010010010000 | |
010010010000 | |
000000000000 | |
000000000000 | |
000000000000 | |
000000000000 | |
000011201000 | |
000011201000 | |
000011201000 | |
000011201000 | |
000011201000 | |
000011201000 | |
000201201000 | |
000201201000 | |
000081204000 | |
000081204000 | |
000041204000 | |
000041204000 | |
000011084000 | |
000011084000 | |
000005044000 | |
000005044000 | |
000080880080 | |
000080880080 | |
000000000000 | |
000000000000 | |
000804080080 | |
000804080080 | |
000000000000 | |
000000000000 | |
000080880080 | |
000080880080 | |
000000000000 | |
000000000000 | |
000000000000 | |
000000000000 | |
000000000000 | |
000000000000 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
`default_nettype none | |
module piano | |
#( | |
parameter real CLK_FREQ = 100e6, // クロック周波数 (Hz) | |
parameter int PDM_WIDTH = 16, // PDM ビット幅 | |
parameter int SINE_WIDTH = 25, // 正弦波ビット幅 | |
parameter int SINE_K_WIDTH = 18, // 正弦波発生式の係数ビット幅 | |
parameter real BASE_FREQ = 442.0, // 正弦波周波数 | |
parameter real SINE_AMP = 0.98, // 正弦波振幅 ( < 1) | |
parameter int NKEYS = 48, // 鍵の数 | |
parameter int NBUTTONS = 4 // 入力ボタンの数 | |
) | |
( | |
input wire clk, | |
input wire [NBUTTONS-1:0] btn_in, // ボタン入力 | |
input wire play_ctrl_in, // スタート・ストップボタン入力 | |
output logic led_out, | |
output logic pulse_out | |
); | |
// ボタン入力に対応させる鍵盤の番号 | |
localparam bit [$clog2(NKEYS)-1:0] BUTTON_NO[NBUTTONS] = '{ | |
22, 21, 19, 17 // ファ,ミ,レ,ド | |
}; | |
logic [NKEYS-1:0] en; // 正弦波生成のイネーブル | |
logic signed [SINE_WIDTH-1:0] sine[NKEYS]; // 正弦波の出力データ | |
logic [NKEYS-1:0] autoplayer_out; // 自動演奏によるイネーブル出力 | |
// 正弦波生成 | |
for (genvar i = 0; i < NKEYS; i++) begin | |
sine_wave_generator | |
#( | |
.CLK_FREQ(CLK_FREQ), | |
.WIDTH(SINE_WIDTH), | |
.K_WIDTH(SINE_K_WIDTH), | |
.TARGET_FREQ(n2freq(i - 26)), // 周波数の指定 | |
.AMP(SINE_AMP) | |
) | |
sine_wave_generator_inst | |
( | |
.clk(clk), | |
.en_in(en[i]), | |
.dout(sine[i]) | |
); | |
end | |
// 自動演奏 | |
autoplayer | |
#( | |
.CLK_FREQ(CLK_FREQ), | |
.MM(140) // テンポの設定 | |
) | |
autoplayer_inst | |
( | |
.clk(clk), | |
.ctrl_in(play_ctrl_in), | |
.en_out(autoplayer_out) | |
); | |
always_comb begin // 自動演奏によるイネーブルとボタン入力の論理和 | |
en = autoplayer_out; | |
for (int i = 0; i < NBUTTONS; i++) | |
en |= btn_in[i] << BUTTON_NO[i]; | |
end | |
// パイプライン型ツリー加算器 | |
localparam int N_ARY = 4; // 木の基数 | |
localparam int N_L1 = $ceil(real'(NKEYS) / N_ARY); // L1 のノード数 | |
localparam int N_L2 = $ceil(real'(N_L1) / N_ARY); // L2 のノード数 | |
logic signed [(SINE_WIDTH+2)-1:0] lv1_sum_reg[N_L1] = '{default: '0}; | |
logic signed [(SINE_WIDTH+4)-1:0] lv2_sum_reg[N_L2] = '{default: '0}; | |
logic signed [(SINE_WIDTH+6)-1:0] all_sum_reg = '0; | |
// L1 の加算 | |
logic signed [(SINE_WIDTH+2)-1:0] lv1_sum[N_L1]; | |
always_comb begin | |
for (int i = 0; i < NKEYS; i += N_ARY) begin | |
lv1_sum[i / N_ARY] = '0; | |
for (int j = 0; j < N_ARY && (i + j) < NKEYS; j++) | |
lv1_sum[i / N_ARY] += sine[i + j]; | |
end | |
end | |
// L2 の加算 | |
logic signed [(SINE_WIDTH+4)-1:0] lv2_sum[N_L2]; | |
always_comb begin | |
for (int i = 0; i < N_L1; i += N_ARY) begin | |
lv2_sum[i / N_ARY] = '0; | |
for (int j = 0; j < N_ARY && (i + j) < N_L1; j++) | |
lv2_sum[i / N_ARY] += lv1_sum_reg[i + j]; | |
end | |
end | |
// ツリー加算器のパイプライン | |
always @(posedge clk) begin | |
lv1_sum_reg <= lv1_sum; | |
lv2_sum_reg <= lv2_sum; | |
all_sum_reg <= lv2_sum_reg[0] + lv2_sum_reg[1] + lv2_sum_reg[2]; | |
end | |
// デルタシグマ変調 | |
logic [PDM_WIDTH-1:0] data_for_pdm = '0; // デルタシグマ変調の入力データ | |
always @(posedge clk) begin // オフセットバイナリへ変換 | |
data_for_pdm <= {~all_sum_reg[(SINE_WIDTH+6)-1], | |
all_sum_reg[(SINE_WIDTH+6)-2-:(PDM_WIDTH-1)]}; | |
end | |
delta_sigma | |
#( | |
.WIDTH(PDM_WIDTH) | |
) | |
delta_sigma_inst | |
( | |
.clk(clk), | |
.data_in(data_for_pdm), | |
.pulse_out(pulse_out) | |
); | |
assign led_out = pulse_out; // 確認用 LED 出力 | |
// 基準音の距離から周波数を計算する関数 | |
function real n2freq(int n); | |
return ((2.0 ** (n / 12.0)) * BASE_FREQ); | |
endfunction | |
endmodule | |
`default_nettype wire |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
`default_nettype none | |
module piano_artytop | |
( | |
input wire clk, | |
input wire [3:0] btn_in, | |
input wire ck_rst_in, | |
output logic led_out, | |
output logic pulse_out | |
); | |
localparam real CLK_FREQ = 100e6; // クロック周波数: 100MHz | |
localparam real STABLE_TIME = 1e-3; // 安定判定時間: 1 ms | |
logic [3:0] btn_sync; | |
logic play_ctrl_sync; | |
// シクロナイザつきデバウンサ | |
for (genvar i = 0; i < 4; i++) begin | |
sync_and_debounce | |
#( | |
.CLK_FREQ(CLK_FREQ), | |
.STABLE_TIME(STABLE_TIME) | |
) | |
sync_and_debounce_btn | |
( | |
.clk(clk), | |
.din(btn_in[i]), | |
.dout(btn_sync[i]) | |
); | |
end | |
sync_and_debounce | |
#( | |
.CLK_FREQ(CLK_FREQ), | |
.STABLE_TIME(STABLE_TIME) | |
) | |
sync_and_debounce_btn | |
( | |
.clk(clk), | |
.din(~ck_rst_in), // アクティブ Low ボタンのため反転 | |
.dout(play_ctrl_sync) | |
); | |
// ピアノモジュール | |
piano | |
#( | |
.CLK_FREQ(CLK_FREQ), | |
.PDM_WIDTH(16), | |
.SINE_WIDTH(25), | |
.SINE_K_WIDTH(18), | |
.BASE_FREQ(442.0), | |
.SINE_AMP(0.98), | |
.NKEYS(48), | |
.NBUTTONS(4) | |
) | |
piano_inst | |
( | |
.clk(clk), | |
.btn_in(btn_sync), | |
.play_ctrl_in(play_ctrl_sync), | |
.led_out(led_out), | |
.pulse_out(pulse_out) | |
); | |
endmodule | |
`default_nettype wire |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
## Clock signal | |
set_property -dict { PACKAGE_PIN E3 IOSTANDARD LVCMOS33 } [get_ports { clk }]; | |
create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports { clk }]; | |
## LED | |
set_property -dict { PACKAGE_PIN H5 IOSTANDARD LVCMOS33 } [get_ports { led_out }]; | |
## Buttons | |
set_property -dict { PACKAGE_PIN D9 IOSTANDARD LVCMOS33 } [get_ports { btn_in[0] }]; | |
set_property -dict { PACKAGE_PIN C9 IOSTANDARD LVCMOS33 } [get_ports { btn_in[1] }]; | |
set_property -dict { PACKAGE_PIN B9 IOSTANDARD LVCMOS33 } [get_ports { btn_in[2] }]; | |
set_property -dict { PACKAGE_PIN B8 IOSTANDARD LVCMOS33 } [get_ports { btn_in[3] }]; | |
set_property -dict { PACKAGE_PIN C2 IOSTANDARD LVCMOS33 } [get_ports { ck_rst_in }]; | |
## Pmod Header JA | |
set_property -dict { PACKAGE_PIN G13 IOSTANDARD LVCMOS33 } [get_ports { pulse_out }]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
`default_nettype none | |
`timescale 1ns/1ps | |
module sim_piano_artytop; | |
localparam real CLOCK_PERIOD_NS = 10; | |
localparam int N = 400000; | |
logic clk, ck_rst_in, pulse_out, led_out; | |
logic [3:0] btn_in; | |
piano_artytop piano_artytop_inst | |
( | |
.clk(clk), | |
.btn_in(btn_in), | |
.ck_rst_in(ck_rst_in), | |
.led_out(led_out), | |
.pulse_out(pulse_out) | |
); | |
initial begin | |
clk = 1'b0; | |
forever begin | |
#(CLOCK_PERIOD_NS / 2.0) | |
clk = 1'b1; | |
#(CLOCK_PERIOD_NS / 2.0) | |
clk = 1'b0; | |
end | |
end | |
initial begin | |
btn_in = 4'b0000; | |
ck_rst_in = 1'b1; | |
#(CLOCK_PERIOD_NS * N) | |
btn_in = 4'b0001; | |
#(CLOCK_PERIOD_NS * N) | |
btn_in = 4'b0011; | |
#(CLOCK_PERIOD_NS * N) | |
btn_in = 4'b0010; | |
#(CLOCK_PERIOD_NS * N) | |
btn_in = 4'b0000; | |
#(CLOCK_PERIOD_NS * N) | |
btn_in = 4'b1100; | |
#(CLOCK_PERIOD_NS * N) | |
btn_in = 4'b000; | |
#(CLOCK_PERIOD_NS * N) | |
$finish; | |
end | |
// ローパスフィルタ | |
localparam real R = 22.2e3; // 22.2kohm | |
localparam real C = 100.0e-12; // 100 pf | |
localparam real DELTA_T_NS = 1.0; | |
localparam real DELTA_T = DELTA_T_NS * 1.0e-9; | |
real v_in, v_out = 0.0; | |
always #DELTA_T_NS begin | |
v_in = pulse_out? 3.3: 0.0; | |
v_out = (R * C * v_out + DELTA_T * v_in) / (R * C + DELTA_T); | |
end | |
endmodule | |
`default_nettype wire |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
`default_nettype none | |
module sine_wave_generator | |
#( | |
parameter real CLK_FREQ = 100e6, // クロック周波数 (Hz) | |
parameter int WIDTH = 25, // データビット幅 | |
parameter int K_WIDTH = 18, // 係数 k のビット幅 | |
parameter real TARGET_FREQ = 100, // 生成波の周波数 | |
parameter real AMP = 0.98 // 生成波の振幅 ( < 1) | |
) | |
( | |
input wire clk, | |
input wire en_in, // イネーブル入力 | |
output logic [WIDTH-1:0] dout | |
); | |
localparam real PI = 3.14159265358979323846; // 円周率 | |
localparam real K = 4.0 * PI * TARGET_FREQ / CLK_FREQ; // 係数 k | |
localparam real G0 = AMP * $cos(2.0 * PI * TARGET_FREQ / CLK_FREQ); // 初期値 | |
localparam int K_Q = calc_shift_amount(K, K_WIDTH - 1); // k の小数部ビット幅 | |
localparam bit signed [K_WIDTH-1:0] K_V = K * (2.0 ** K_Q); // 正規化された k | |
logic signed [WIDTH-1:0] freg = '0; // sin レジスタ | |
logic signed [WIDTH-1:0] greg = G0 * (2.0 ** (WIDTH-1)); // cos レジスタ | |
logic signed [WIDTH-1:0] kterm; // 係数 k の乗算結果 | |
logic is_ringing = 1'b0; // 発振状態レジスタ | |
logic turn = 1'b0; // リープフロッグ状態レジスタ | |
logic zero_crossed; // ゼロクロス検出フラグ | |
logic previous_sign = 1'b0; // 1クロック前の出力値の符号 | |
// 発振開始・停止の状態制御 | |
always @(posedge clk) begin | |
if (!is_ringing && en_in) | |
is_ringing <= 1'b1; | |
else if (!en_in && zero_crossed) | |
is_ringing <= 1'b0; | |
end | |
// リープフロッグの状態制御 | |
always @(posedge clk) begin | |
if (!is_ringing) | |
turn <= '0; | |
else | |
turn <= !turn; | |
end | |
// 乗算 | |
assign kterm = ((K_WIDTH+WIDTH)'(K_V) * (!turn? greg: freg)) >>> K_Q; | |
// レジスタ更新 | |
always @(posedge clk) begin | |
if (!is_ringing) begin | |
freg <= '0; | |
greg <= G0 * (2.0 ** (WIDTH-1)); | |
end | |
else begin | |
if (!turn) | |
freg <= freg + kterm; | |
else | |
greg <= greg - kterm; | |
end | |
end | |
// 出力 | |
assign dout = freg; | |
// 1クロック前の符号を保存しゼロクロスを検出 | |
always @(posedge clk) begin | |
previous_sign <= dout[WIDTH-1]; | |
end | |
assign zero_crossed = (dout[WIDTH-1] != previous_sign); | |
// 数値 x を width ビットで正規化するのに必要なシフト量を求める関数 | |
function int calc_shift_amount(real x, int width); | |
longint t; | |
int q; | |
for (t = x, q = 0; !t[width-1] && q < 128; q++) // シフトの最大値を128に制限 | |
t = x * (2.0 ** (q + 1)); | |
return q; | |
endfunction | |
endmodule | |
`default_nettype wire |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
`default_nettype none | |
module sync_and_debounce | |
#( | |
parameter real CLK_FREQ = 100e6, // クロック周波数 (Hz) | |
parameter real STABLE_TIME = 1e-3 // 安定したと判定するまでの時間 (秒) | |
) | |
( | |
input wire clk, | |
input wire din, | |
output logic dout = 1'b0 | |
); | |
// 2段のシフトレジスタによるシンクロナイザ | |
logic din_meta = 1'b0, din_sync = 1'b0; | |
always @(posedge clk) begin | |
din_meta <= din; // メタステーブルの危険あり | |
din_sync <= din_meta; // 同期化された入力信号 | |
end | |
// デバウンス用カウンタのビット幅と最大値 | |
localparam int COUNT_WIDTH = $clog2(int'(STABLE_TIME * CLK_FREQ)); | |
localparam bit [COUNT_WIDTH-1:0] MAX_COUNT = STABLE_TIME * CLK_FREQ - 1; | |
// カウンタ | |
logic [COUNT_WIDTH-1:0] count = '0; | |
always @(posedge clk) begin | |
if (din_sync != dout) begin // 入力と出力が異なるならカウンタを進める | |
if (count == MAX_COUNT) | |
count <= '0; | |
else | |
count <= count + 1'b1; | |
end | |
else // 入力と出力が同じならカウンタをクリア | |
count <= '0; | |
end | |
// 出力レジスタ | |
always @(posedge clk) begin | |
// カウンタが最大値まで達したら入力の変化を出力に伝える | |
if (din_sync != dout && count == MAX_COUNT) | |
dout <= din_sync; | |
end | |
endmodule | |
`default_nettype wire |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment