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];