MyHDL реализация для CORDIC на гитхаб. Плюсами данной реализации можно считать автоматизацию процесса расчета необходимых параметров для алгоритма, таких как углы, усиление, нужное количество итераций.
Из очевидных плюсов MyHDL - можно строить графики в python используя данные из тестбенча. Например:
Тут посчитан спектр в дБ для одной из квадратур. Для этого необходимо всего лишь запустить симуляцию testbench на 10000 итераций
И посчитать БПФ
Чтобы получить .v файлы нужно воспользоваться этой частью:
И тогда получившийся файл:
Из очевидных плюсов MyHDL - можно строить графики в python используя данные из тестбенча. Например:
Тут посчитан спектр в дБ для одной из квадратур. Для этого необходимо всего лишь запустить симуляцию testbench на 10000 итераций
N = 16 f = 500 F = 8000 inst = traceSignals(tb, N, f, F) sim = Simulation(inst) sim.run(10000)
И посчитать БПФ
N_FFT = 128 fig, ax = plt.subplots(3,1) ax[0].plot(plt_clk[-1-N_FFT:-1:1],'ro-') ax[1].plot(plt_cnt[-1-N_FFT:-1:1],'bo-') N_FFT = 4096 freq = [float(i)*F/N_FFT for i in range(N_FFT)] X = np.fft.fft(plt_cnt[-1-N_FFT:-1:1]) + float(N_FFT)/1000 mags = abs(X) / max(abs(X)) X_db = 20*np.log10(mags) ax[2].plot(freq, X_db) fig.tight_layout()
Чтобы получить .v файлы нужно воспользоваться этой частью:
n = 16 n_signed = n - 1 i_clk = Signal(bool(0)) i_rst = Signal(bool(0)) i_en = Signal(bool(0)) o_Re = Signal(intbv(0, -2**n_signed, 2**n_signed)) o_Im = Signal(intbv(0, -2**n_signed, 2**n_signed)) f = 2000 F = 8000 freq = Signal(intbv(f,0,2**f.bit_length())) discr_freq = Signal(intbv(F, 0, 2**F.bit_length())) uut = toVerilog(Cordic_generator, i_clk, i_rst, i_en, freq, discr_freq, o_Re, o_Im, n)
И тогда получившийся файл:
// File: top.v
// Generated by MyHDL 0.8.1
// Date: Sun Mar 8 17:55:47 2015
`timescale 1ns/10ps
module top (
i_clk,
i_rst,
i_en,
i_freq,
i_discr_freq,
o_Re,
o_Im
);
input i_clk;
input i_rst;
input i_en;
input [10:0] i_freq;
input [12:0] i_discr_freq;
output signed [15:0] o_Re;
wire signed [15:0] o_Re;
output signed [15:0] o_Im;
wire signed [15:0] o_Im;
wire [15:0] w_rem_next;
wire [14:0] o_reminder;
reg [14:0] r_quo;
wire [29:0] DIVIDENT;
wire [14:0] o_quotient;
wire [14:0] DISCR_FREQ;
reg [14:0] r_rem;
reg [15:0] w_quo_next;
reg [4:0] uut_0_r_cnt;
wire signed [60:0] uut_0_w_dif;
reg [59:0] uut_0_r_divider_copy;
reg [29:0] uut_0_r_quotient;
reg [59:0] uut_0_r_reminder;
reg [29:0] uut_0_r_quotient_out;
reg [29:0] uut_0_r_reminder_out;
reg [1:0] uut_1_r_quad [0:14-1];
reg signed [14:0] uut_1_angle [0:14-1];
reg signed [16:0] uut_1_w_Re [0:14-1];
reg signed [15:0] uut_1_r_Re [0:15-1];
reg signed [15:0] uut_1_r_Im [0:15-1];
reg signed [16:0] uut_1_w_Im [0:14-1];
reg signed [14:0] uut_1_r_input_arg [0:15-1];
reg signed [14:0] uut_1_r_output_arg [0:14-1];
assign DIVIDENT = (i_freq << 15);
assign DISCR_FREQ = i_discr_freq;
assign w_rem_next = (r_rem + o_reminder);
always @(w_rem_next, DISCR_FREQ, r_quo, o_quotient) begin: TOP_COMB2
if ((w_rem_next >= DISCR_FREQ)) begin
w_quo_next = ((r_quo + o_quotient) + 1);
end
else begin
w_quo_next = (r_quo + o_quotient);
end
end
always @(posedge i_clk) begin: TOP_SEQ
if ((w_rem_next >= DISCR_FREQ)) begin
r_rem <= (w_rem_next - DISCR_FREQ);
if ((w_quo_next[(15 + 1)-1:15] == 1)) begin
r_quo <= (w_quo_next - (2 ** 15));
end
else begin
r_quo <= w_quo_next;
end
end
else begin
r_rem <= w_rem_next;
if ((w_quo_next[(15 + 1)-1:15] == 1)) begin
r_quo <= (w_quo_next - (2 ** 15));
end
else begin
r_quo <= w_quo_next;
end
end
end
assign uut_0_w_dif = (uut_0_r_reminder - (uut_0_r_divider_copy >>> uut_0_r_cnt));
assign o_quotient = uut_0_r_quotient_out;
assign o_reminder = uut_0_r_reminder_out;
always @(posedge i_clk, negedge i_rst) begin: TOP_UUT_0_SEQ
if ((i_rst == 0)) begin
uut_0_r_cnt <= 0;
uut_0_r_quotient <= 0;
uut_0_r_reminder <= 0;
uut_0_r_divider_copy <= 0;
uut_0_r_quotient_out <= 0;
uut_0_r_reminder_out <= 0;
end
else if ((i_en == 1)) begin
uut_0_r_cnt <= ((uut_0_r_cnt + 1) % 30);
if ((uut_0_r_cnt == 0)) begin
uut_0_r_quotient <= 0;
uut_0_r_reminder <= DIVIDENT;
uut_0_r_divider_copy <= ($signed({1'b0, i_discr_freq}) << (30 - 1));
uut_0_r_quotient_out <= uut_0_r_quotient;
uut_0_r_reminder_out <= uut_0_r_reminder[30-1:0];
end
else begin
if ((uut_0_w_dif >= 0)) begin
uut_0_r_quotient <= ((uut_0_r_quotient << 1) + 1);
uut_0_r_reminder <= uut_0_w_dif;
end
else begin
uut_0_r_quotient <= (uut_0_r_quotient << 1);
end
end
end
end
always @(uut_1_r_Re[0], uut_1_r_Re[1], uut_1_r_Re[2], uut_1_r_Re[3], uut_1_r_Re[4], uut_1_r_Re[5], uut_1_r_Re[6], uut_1_r_Re[7], uut_1_r_Re[8], uut_1_r_Re[9], uut_1_r_Re[10], uut_1_r_Re[11], uut_1_r_Re[12], uut_1_r_Re[13], uut_1_r_Re[14], uut_1_r_Im[0], uut_1_r_Im[1], uut_1_r_Im[2], uut_1_r_Im[3], uut_1_r_Im[4], uut_1_r_Im[5], uut_1_r_Im[6], uut_1_r_Im[7], uut_1_r_Im[8], uut_1_r_Im[9], uut_1_r_Im[10], uut_1_r_Im[11], uut_1_r_Im[12], uut_1_r_Im[13], uut_1_r_Im[14]) begin: TOP_UUT_1_COMB
integer i;
for (i=1; i<14; i=i+1) begin
uut_1_w_Re[i] = $signed((uut_1_r_Re[(i - 1)] + (1 << (i - 1))) >>> i);
uut_1_w_Im[i] = $signed((uut_1_r_Im[(i - 1)] + (1 << (i - 1))) >>> i);
end
end
always @(posedge i_clk, negedge i_rst) begin: TOP_UUT_1_SEQ
integer i;
if ((i_rst == 0)) begin
for (i=0; i<14; i=i+1) begin
uut_1_r_input_arg[i] <= 0;
uut_1_r_output_arg[i] <= 0;
uut_1_r_quad[i] <= 0;
uut_1_r_Re[i] <= 0;
uut_1_r_Im[i] <= 0;
case (i)
0: uut_1_angle[i] <= 4096;
1: uut_1_angle[i] <= 2418;
2: uut_1_angle[i] <= 1278;
3: uut_1_angle[i] <= 649;
4: uut_1_angle[i] <= 326;
5: uut_1_angle[i] <= 163;
6: uut_1_angle[i] <= 81;
7: uut_1_angle[i] <= 41;
8: uut_1_angle[i] <= 20;
9: uut_1_angle[i] <= 10;
10: uut_1_angle[i] <= 5;
11: uut_1_angle[i] <= 3;
12: uut_1_angle[i] <= 1;
default: uut_1_angle[i] <= 1;
endcase
end
end
else begin
if ((i_en == 1)) begin
uut_1_r_input_arg[0] <= r_quo[(15 - 2)-1:0];
uut_1_r_output_arg[0] <= uut_1_angle[0];
uut_1_r_quad[0] <= r_quo[15-1:(15 - 2)];
uut_1_r_Re[0] <= 19897;
uut_1_r_Im[0] <= 19897;
for (i=1; i<14; i=i+1) begin
uut_1_r_input_arg[i] <= uut_1_r_input_arg[(i - 1)];
uut_1_r_quad[i] <= uut_1_r_quad[(i - 1)];
if ((uut_1_r_output_arg[(i - 1)] > uut_1_r_input_arg[(i - 1)])) begin
uut_1_r_Re[i] <= (uut_1_r_Re[(i - 1)] + uut_1_w_Im[i]);
uut_1_r_Im[i] <= (uut_1_r_Im[(i - 1)] - uut_1_w_Re[i]);
uut_1_r_output_arg[i] <= (uut_1_r_output_arg[(i - 1)] - uut_1_angle[i]);
end
else begin
uut_1_r_Re[i] <= (uut_1_r_Re[(i - 1)] - uut_1_w_Im[i]);
uut_1_r_Im[i] <= (uut_1_r_Im[(i - 1)] + uut_1_w_Re[i]);
uut_1_r_output_arg[i] <= (uut_1_r_output_arg[(i - 1)] + uut_1_angle[i]);
end
end
if ((uut_1_r_quad[(14 - 1)] == 0)) begin
uut_1_r_Re[14] <= uut_1_r_Re[(14 - 1)];
uut_1_r_Im[14] <= uut_1_r_Im[(14 - 1)];
end
else if ((uut_1_r_quad[(14 - 1)] == 1)) begin
uut_1_r_Re[14] <= (-uut_1_r_Im[(14 - 1)]);
uut_1_r_Im[14] <= uut_1_r_Re[(14 - 1)];
end
else if ((uut_1_r_quad[(14 - 1)] == 2)) begin
uut_1_r_Re[14] <= (-uut_1_r_Re[(14 - 1)]);
uut_1_r_Im[14] <= (-uut_1_r_Im[(14 - 1)]);
end
else if ((uut_1_r_quad[(14 - 1)] == 3)) begin
uut_1_r_Re[14] <= uut_1_r_Im[(14 - 1)];
uut_1_r_Im[14] <= (-uut_1_r_Re[(14 - 1)]);
end
end
end
end
assign o_Re = uut_1_r_Re[14];
assign o_Im = uut_1_r_Im[14];
endmodule

Доброго времени суток.
ОтветитьУдалить1) в TOP_UUT_1_SEQ в случае с case(i) идентификаторы регистров из массива будут совпадать со значением i. т.е. при "0: uut_1_angle[0]".
таким образом, для упрощения, лучше вынести этот блок за always в initial begin -> end.
2) при выборе итераций для соответствующей четверти, можно использовать биты и битовые операции для quad. например,
Re[14] <= (^quad[13]) ? -Re[13] : Re[13];