前回の記事を再掲します。
プリエンファシスのブロック図
ここで、fs=152kHzのときのパラメータは次の通りです。
k: 0.75 (2進 0.11)
b: 0.04541 (2進 0.00001011101)
G: 20.875 (2進 10100.111)
ブロック図によると、処理の過程で k倍とか 1+b倍とかの乗算処理を多用しています。前回は、乗算器を節約するため乗算処理をシフト演算と加算に分解していました。今回は、先のローパスフィルタを参考にして、1個の乗算器を使い入力信号を適宜切り替えています。乗算器は前回と同じハードマクロをインスタンシエーションしていますのでレイテンシの3を考慮して、タイミング関係を作図したうえでコードを作成しました。※state512は1クロック位置がずれています。わかりやすさ優先であえて直していません
タイミング関係
特性実測値
周波数特性(入力ローパスフィルタ含む)
スペクトル(5kHz、プリエンファシスON)
※赤い波形はバッグクラウンドノイズ
スペクトル(5kHz、プリエンファシスOFF)
一見しただけでは、何をやっているかさっぱりわからないシロモノになってしまいました。タイミング関係図と合わせて見て下さい。また、計算のダイナミックレンジの取り方を配慮できていないので、ビット幅が不足しているところと過剰なところが混在していると思います。出力レジスタのサチュレーション処理はローパスフィルタのコードを使わせて頂いています。
module pre_emph(
pe_l_i, pe_r_i, pe_l_o, pe_r_o,
clk, en, reset, pe_thru
);
input [23:0] pe_l_i;
input [23:0] pe_r_i;
output [23:0] pe_l_o;
output [23:0] pe_r_o;
input clk;
input en;
input reset;
input pe_thru;
reg [8:0] state512;
reg [35:0] input_reg;
reg [17:0] mul_in1;
reg [17:0] mul_in2;
wire [35:0] mul_out;
reg [35:0] reg0;
reg [35:0] reg1;
reg [17:0] reg2_l;
reg [17:0] reg2_r;
reg [17:0] reg2_l2;
reg [17:0] reg2_r2;
reg [35:0] delay_buff;
reg [29:0] output_reg_l;
reg [29:0] output_reg_r;
reg [23:0] pe_l_o;
reg [23:0] pe_r_o;
// State counter
always @(posedge clk or posedge reset)
begin
if (reset)
state512 <= 0;
else if (state512 == 511)
state512 <= 0;
else
state512 <= state512 + 1;
end
assign latch_out = (state512 == 17);
// Pre Emphasis
always @(posedge clk or posedge reset)
begin
if (reset)
begin
input_reg <= 0;
mul_in1 <= 0;
mul_in2 <= 0;
reg0 <= 0;
reg1 <= 0;
delay_buff <= 0;
output_reg_l <= 0;
output_reg_r <= 0;
end
else
begin
case (state512)
0: begin
input_reg <= {pe_l_i[23:6], pe_r_i[23:6]}; // Vin(L/R)
end
1: begin
mul_in1 <= input_reg[35:18]; // Vin(L)
mul_in2 <= 18'b01_1000_0000_0000_0000; // k=0.75 (0.11)
end
2: begin
mul_in1 <= input_reg[17:0]; // Vin(R)
mul_in2 <= 18'b01_1000_0000_0000_0000; // k=0.75 (0.11)
end
3: begin
mul_in1 <= delay_buff[35:18]; // delay_buf(L)
mul_in2 <= 18'b00_1000_0000_0000_0000; // k=1-0.75=0.25 (0.01)
end
4: begin
mul_in1 <= delay_buff[17:0]; // delay_buf(R)
mul_in2 <= 18'b00_1000_0000_0000_0000; // k=1-0.75=0.25 (0.01)
end
5: begin
mul_in1 <= 0;
mul_in2 <= 0;
reg0[35:18] <= mul_out[34:17];
end
6: begin
reg0[17:0] <= mul_out[34:17];
end
7: begin
mul_in1 <= input_reg[35:18]; // Vin(L)
mul_in2 <= 18'b01_0000_1011_1010_0000; // 1+b=1.04541 (01.00001011101)
reg1[35:18] <= mul_out[34:17];
end
8: begin
mul_in1 <= input_reg[17:0]; // Vin(R)
mul_in2 <= 18'b01_0000_1011_1010_0000; // 1+b=1.04541 (01.00001011101)
reg1[17:0] <= mul_out[34:17];
end
9: begin
reg2_l <= reg0[35:18] + reg1[35:18];
reg2_r <= reg0[17:0] + reg1[17:0];
end
10:begin
reg2_l2 <= ~reg2_l + 1;
reg2_r2 <= ~reg2_r + 1;
end
11:begin
mul_in1 <= mul_out[34:17] + {reg2_l2[17], reg2_l2[17:1]}; // preemph(L)
mul_in2 <= 18'b01_0100_1110_0000_0000; // G=20.875 (010100.111)
delay_buff <= {reg2_l, reg2_r};
end
12:begin
mul_in1 <= mul_out[34:17] + {reg2_r2[17], reg2_r2[17:1]}; // preemph(R)
mul_in2 <= 18'b01_0100_1110_0000_0000; // G=20.875 (010100.111)
end
15:begin
output_reg_l <= mul_out[34:5]; // Vout(L)
end
16:begin
output_reg_r <= mul_out[34:5]; // Vout(R)
end
default: begin
mul_in1 <= 0;
mul_in2 <= 0;
end
endcase
end
end
// output data register, saturation
always @(posedge clk or posedge reset)
begin
if (reset)
begin
pe_l_o <= 0;
pe_r_o <= 0;
end
else if (pe_thru)
begin
pe_l_o <= pe_l_i;
pe_r_o <= pe_r_i;
end
else if (latch_out)
begin
// left channel
if (~output_reg_l[29] && !(output_reg_l[28:23] == 6'b000000))
pe_l_o <= 8388607; // 24-bit positive max
else if (output_reg_l[29] && !(output_reg_l[28:23] == 6'b111111))
pe_l_o <= -8388608; // 24-bit negative max
else
pe_l_o <= {output_reg_l[29], output_reg_l[22:0]};
// right channel
if (~output_reg_r[29] && !(output_reg_r[28:23] == 6'b000000))
pe_r_o <= 8388607; // 24-bit positive max
else if (output_reg_r[29] && !(output_reg_r[28:23] == 6'b111111))
pe_r_o <= -8388608; // 24-bit negative max
else
pe_r_o <= {output_reg_r[29], output_reg_r[22:0]};
end
end
mul_p U1 (
.clk(clk),
.sclr(reset),
.a(mul_in1),
.b(mul_in2),
.p(mul_out)
);
endmodule
速度の低下
プリエンファシスのモジュールの有無で最大動作周波数が下がってしまいました。できるだけ処理を細切れにしたつもりでしたが時間的に厳しいところもあるようです。
プリエンファシスあり
プリエンファシスなし
0 件のコメント:
コメントを投稿