вторник, 10 марта 2015 г.

MyHDL и CORDIC

MyHDL реализация для CORDIC на гитхаб. Плюсами данной реализации можно считать автоматизацию процесса расчета необходимых параметров для алгоритма, таких как углы, усиление, нужное количество итераций.
Из очевидных плюсов 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 комментарий:

  1. Доброго времени суток.
    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];

    ОтветитьУдалить