Yuri Panchul (panchul) wrote,
Yuri Panchul
panchul

Конкурентное преимущество молодого инженера - одинаково легкое владение хардвером и софтвером

Господа! В сегодняшней суровой международной обстановке перед каждым молодым российским или украинским инженером встает вопрос: как повысить свою технологическую конкурентоспособность, не опускаясь до похищения технологий у американских налогоплательщиков?

Один из способов получения нечестного конкурентного преимущества: учиться на чужих ошибках. Повторяющаяся ошибка в хайтеке: человек специализируется либо в чистом хардвере, либо в чистом софтвере, после чего пытается софтверным способом решить проблему, которую лучше решать в хадвере, или наоборот. Как это предотвратить: натренировать у себя способность одинаково легко писать софтвер и дизайнить хардвер, хотя бы на простом уровне (а потом стать еще и узким специалистом в чем-то, но это тема другой беседы).

Для того, чтобы приобрести в чем-то легкость, нужно много играться, начиная от простых примеров. В качестве одной из возможных отправных точек для школьников и младших студентов я смастерил примерчик, в котором софтвер на микроконтроллере Microchip PIC32 разговаривает с хардвером имплементированным в FPGA Altera Cyclone IV. Можно придумать сотни примеров задачек, которые можно решить 1) чисто в софтвере 2) чисто в хардвере и 3) наполовину так, наполовину сяк. Мой примерчик вычисляет на FPGA простую математическую формулу с аргументами, полученными от софтвера, после чего софтвер сравнивает результат с ожидаемым. При этом формула вычисляется за несколько тактов, используя просто конечный автомат. О результатах мое демо-устройство из нескольких плат (которое я описал в http://panchul.livejournal.com/220998.html ) сообщает на головной компьютер, используя UART, USB port и утилиту Putty ( http://en.wikipedia.org/wiki/PuTTY ).

Я размещаю свои примерчики на Google code. Если вы хотите поучаствовать со мной в написании примерчиков для PIC32 в комбинации с разными FPGA - я готов добавить вас в авторы.


Главный кусок программы
http://code.google.com/p/pic32-examples/source/browse/trunk/tedious/011_fpga_coprocessor_ports_3.X/main.c

Главный кусок хардверного дизайна без привязки к конткретной FPGA плате
http://code.google.com/p/pic32-examples/source/browse/trunk/tedious/011_fpga_coprocessor_ports_3.X/fpga/top.v

Топ-модуль с инстанциацией PLL macro от Альтеры для поднятия частоты
http://code.google.com/p/pic32-examples/source/browse/trunk/tedious/011_fpga_coprocessor_ports_3.X/fpga/de0_nano/de0_nano.v

PLL macro от Альтеры для поднятия частоты
http://code.google.com/p/pic32-examples/source/browse/trunk/tedious/011_fpga_coprocessor_ports_3.X/fpga/de0_nano/pll50_200.v

Конфигурация для микроконтроллера Microchip PIC32MX320F128H
http://code.google.com/p/pic32-examples/source/browse/trunk/tedious/library/config.c


А для критики своего примерчика я использовал не только уже знакомого вам Сергея Вакуленко, но и сурового эксперта по FPGA - автора книги 100 Power Tips For FPGA Designers американского инженера ленинградского происхождения Евгения Ставинова (не)известного в ЖЖ как outputlogic. Евгений работал в ведущей FPGA компании Xilinx, а сейчас работает в LeCroy - компании, которая производит осциллографы.


http://www.amazon.com/Evgeni-Stavinov/e/B0051RU6RO/ref=ntt_athr_dp_pel_1

Evgeni Stavinov is a longtime FPGA user with over a decade of diverse design experience. Before becoming a hardware architect at SerialTek LLC, he held different engineering positions at Xilinx, LeCroy and CATC. Evgeni holds MS and BS degrees in electrical engineering from University of Southern California and Technion - Israel Institute of Technology. Evgeni is a creator of OutputLogic.com, a portal that offers different online productivity tools.


Нелепость нашей Вселенной заключается в том, что настоящий конкретный эксперт мирового уровня по осциллографам outputlogic имеет всего 18 френдов в ЖЖ, а в это же самое время "стрелка осциллографа" Юлия Латынина - рассуждает об электронике перед миллионной аудиторией.

Короче, мы с Вакуленко сходили с Евгением Ставиновым на ланч, где Евгений помимо обсуждения частот и синхросигналов в FPGA также поделился своими впечатлениями от его недавней поездки в Санкт-Петербург. В Питере мистер Ставинов не был с детства и был неожиданно поражен вежливостью жителей и обилием всякого рода еды.


Эксперт из Xilinx и LeCroy, автор книги по FPGA мистер Ставинов кушает русскую солянку и блины, запивая березовым соком:

http://outputlogic.livejournal.com/3294.html







IMAG1127

А теперь текст переписки меня и товарища Ставинова - для юношей, жаждущих выучить интерфейс между PIC32 и FPGA, получив тем самым конкурентное преимущество перед сверстниками без нарушения американских законов об экспортном контроле:

Юрий Панчул:


Евгений:

Я модифицировал свой примерчик по вашим рекомендациям и было бы очень хорошо, если бы вы его проверили.

Итого:

1. Микроконтроллер PIC32 работает на частоте 80 MHz (SYSCLK) от primary oscillator (кристалла) PLL. Периферийная шина микроконтроллера работает на частоте 10 MHz (PBCLK) которая derived от SYSCLK.

2. Altera Cyclone IV FPGA работает от собственного осциллятора на частоте 50 MHz. Этот clock не имеет никакого relationship c clock-ом микроконтроллера. Внутри дизайна я устанавливаю PLL macro, которое повышает частоту до 200 MHz.

3. Платы микроконтроллера и FPGA соединяют проводки длиной 6 inches.

4. Я использую два слоя регистров (port_e -> data0 -> data а также port_d_in -> tag0 -> tag), чтобы синхронизировать асинхронный сигнал и избежать насколько это практически возможно, метастабильное состояние.

5. Сигналом того, что одна транзакция закончилась, и началась другая, является изменение tag-а – либо с 0 в 1 либо наоборот. State machine сохраняет предыдущий таг, и начинает обработку новой транзакции только если новый так отличается от старого.

6. Когда таг меняется, data (port_e) уже гарантированно содержит valid data (это следует из того, что software устанавливает port_e до port_d, т.е. разница между ними минимум в 1 цикл 10 MHz.

7. То, что результат valid, гарантируется nop-ами на стороне софтвера.

Вопросы:

1. Правильно ли я выбрал соотношение частот (80 10 200)? Насколько можно их варьировать в данной установке?

2. Нужно ли делать два слоя регистров и для data, и для tag? Может быть, делать это только для tag? Ведь data все равно не меняется?

3. Я explicitly instantiate буфера ввода-вывода (см. de0_nano.v) Стоит ли это делать? Может, синтез по умолчанию их instantiate?

4. Я собираюсь сделать похожее демо для Xilinx Spartan. Там есть какие-нибудь методологические отличия для данного примера?

5. У вас в книге есть пример синхронизатора с edge detection. Может его можно приспособить к tag вместо текущего механизма синхронизации? Позволит ли это использовать FPGA на более низкой частоте по сравнению с периферийной шиной?

6. Любые другие замечания по RTL стилю примера?

Спасибо,
Юрий Панчул


Евгений Ставинов:


Hi Yuri,

I'm going to use English - my Russian typing skills are not good.

>> 1. Правильно ли я выбрал соотношение частот (80 10 200)? Насколько можно их варьировать в данной установке?

80MHz doesn't play any role here. Essentially, a 10MHz bus is oversampled with a 200MHz clock. That frequency can be lower. 50MHz is a bit too low, in my opinion.

>> 2. Нужно ли делать два слоя регистров и для data, и для tag? Может быть, делать это только для tag? Ведь data все равно не меняется?

In this case - not really, only the tag. It's implicitly guaranteed that data lines are stable when they're used by the logic (setup/hold requirement is met).
Data lines can be constrained as multi-cycle paths.

In general case - yes. For example, data lines are fed directly into a dedicated memory block of an FPGA. That memory block requires setup/hold time on both control and data inputs. So any instability on data lines can mess up the memory block.


>> 3. Я explicitly instantiate буфера ввода-вывода (см. de0_nano.v) Стоит ли это делать? Может, синтез по умолчанию их instantiate?

No. Simple cases of IO buffers are inferred correctly by all the FPGA synthesis tools. You only need to specify IO type as a constraint (voltage and IO standard).
It's better to explicitly instantiate more complex things, like DDR IOs with controls.


>> 4. Я собираюсь сделать похожее демо для Xilinx Spartan. Там есть какие-нибудь методологические отличия для данного примера?

Not really. You'd need to regenerate Xilinx-specific PLL, and assign constraints.


>> 5. У вас в книге есть пример синхронизатора с edge detection. Может его можно приспособить к tag вместо текущего механизма синхронизации? Позволит ли это использовать FPGA на более низкой частоте по сравнению с периферийной шиной?

It'll work, but I'd not recommend doing it. A simple answer is that this approach violates synchronous design principles.


>> 6. Любые другие замечания по RTL стилю примера?

I'd not recommend inferring multiplication like it's done in top.v. Synthesis tool will take advantage of a special multiplication module, which is FPGA vendor-specific.
So even if it's synthesized correctly, the functionality of the synthesized circuit is not transparent (signed/unsigned, number of clock delays, etc).

I assume the circuit is functionally correct and you've run some functional simulation of this module.

Thanks,
Evgeni


Евгений Ставинов (дополнение):


Hi Yuri,

>> Сигналом того, что одна транзакция закончилась, и началась другая, является изменение tag-а – либо с 0 в 1 либо наоборот. State machine сохраняет предыдущий таг, и начинает обработку новой транзакции только если новый так отличается от старого.

Just want to point out that double-flopping the tag signal doesn't guarantee that recovered signal doesn't contain glitches. For example, 0->1 transition on the input may look like
0->0->1->0->1->1->...

That happens because the first flop may enter a metastable state. All that double-flop circuit guarantees is proper synchronisation of tag transitions on the output to FPGA clock.

There are two ways to deal with this situation:

(1) add a simple filter of 1-2 clock glitches of the recovered tag.

(2) implement phase detection circuit and sample the tag in the middle. So for example if 10MHz tag is oversampled with 100MHz clock, then the tag is sampled every 10 FPGA clocks at unknown phase of 0-9 clocks, which is determined during the power-on. The problem with this approach that the phase has to be adjusted once in a while, because FPGA and peripheral bus clocks are drifting at some rate (at least 40ppm). But then this circuit becomes unnecessarily complex.


Thanks,
Evgeni


Юрий Панчул:


Evgeni:

*** For example, 0->1 transition on the input may look like 0->0->1->0->1->1->... ***

What is this event’s probability under given circumstances? I mean if it happens only once every thousand years this should be fine.

*** (1) add a simple filter of 1-2 clock glitches of the recovered tag. ***

Are you talking about something similar to button debouncing, something like

 
module filter
(
    input      clock,
    input      reset_n,
    input      in,
    output reg out
);
 
    reg [2:0] samples;
 
    always @(posedge clock or negedge reset_n)
    begin
        if (! reset_n)
            samples <= 0;
        else
            samples <= { samples [1:0], in };
    end
 
    always @(posedge clock or negedge reset_n)
    begin
        if (! reset_n)
            out <= 0;
        else
            out <= & samples;
    end
 
endmodule


Thank you,
Yuri Panchul



Евгений Ставинов:


Hi Yuri,

Well, it's hard to quantify how often this is going to happen - it's all about probabilities.
Altera Quartus produces MTBF report that analyzes metastability. Yes, it's usually in units of years. Xilinx has a couple of whitepapers, but as far as I know ISE still doesn't have any metastability-related reports.

Yes, glitch filter looks exactly like button debouncing.

Thanks,
Evgeni






Главный кусок программы
http://code.google.com/p/pic32-examples/source/browse/trunk/tedious/011_fpga_coprocessor_ports_3.X/main.c

Это софтверная сторона:

    . . . . . . . .

    fpga_init ();

    for (n = 0; n < 256; n  )
    {
        PORTE = n;
        PORTD = PORTD_NO_RESET | (n & 1 ? 0 : PORTD_TAG);
        asm volatile ("nop; nop; nop; nop; nop; nop");
        r = PORTD & 0xF;
        output_result (6, n, r);
    }

    . . . . . . . .



Главный кусок хардверного дизайна без привязки к конткретной FPGA плате
http://code.google.com/p/pic32-examples/source/browse/trunk/tedious/011_fpga_coprocessor_ports_3.X/fpga/top.v

Это хардверная сторона:


module top
(
    input         clock,
    input  [7: 0] port_e,
    input  [7: 5] port_d_in,
    output [3: 0] port_d_out,
    output [1:12] display,
    output [7: 0] leds
);

    wire reset_n = port_d_in [5];

    reg [7:0] data0;
    reg       tag0;

    reg [7:0] data;
    reg       tag;

    always @(posedge clock or negedge reset_n)
    begin
        if (! reset_n)
        begin
            data0 <= 0;
            tag0  <= 0;
    
            data  <= 0;
            tag   <= 0;
        end
        else
        begin
            data0 <= port_e;
            tag0  <= port_d_in [6];
    
            data  <= data0;
            tag   <= tag0;
        end
    end

    // Datapath

    reg [7:0] add_a, add_b;
    reg [7:0] mul_a, mul_b;

    wire [7:0] add_result = add_a   add_b;
    wire [7:0] mul_result = mul_a * mul_b;

    // Main state machine - sequential

    reg [7:0] r_add_result;
    reg [7:0] r_mul_result;

    reg [1:0] r_state;
    reg       r_first_tag;
    reg       r_prev_tag;
    reg [3:0] r_result;

    reg [2:0] state;
    reg       first_tag;
    reg       prev_tag;
    reg [3:0] result;

    assign port_d_out = r_result;

    always @(*)
    begin
        state      = r_state;
        first_tag  = r_first_tag;
        prev_tag   = r_prev_tag;
        result     = r_result;

        add_a      = 0;
        add_b      = 0;
        mul_a      = 0;
        mul_b      = 0;
    
        case (r_state)
    
        0:
            if (first_tag || tag != prev_tag)
            begin
                first_tag  = 0;
                prev_tag   = tag;
    
                mul_a      = data;
                mul_b      = data;
    
                state      = 1;
            end
    
        1:
            begin
                add_a      = r_mul_result;
                add_b      = 3;
    
                state      = 2;
            end
    
        2:
            begin
                mul_a      = r_add_result;
                mul_b      = r_add_result;

                state      = 3;
            end
		  
        3:
            begin
                result     = r_mul_result;
                state      = 0;
            end
    
        endcase
    end
    
    always @(posedge clock or negedge reset_n)
    begin
        if (! reset_n)
        begin
            r_add_result  <= 0;
            r_mul_result  <= 0;

            r_state       <= 0;
            r_first_tag   <= 1;
            r_prev_tag    <= 0;
    
            r_result      <= 0;
        end
        else
        begin
            r_add_result  <= add_result;
            r_mul_result  <= mul_result;

            r_state       <= state;
            r_first_tag   <= first_tag;
            r_prev_tag    <= prev_tag;

            r_result      <= result;
        end
    end

    display_driver display_driver_inst
    (
        .clock          ( clock                    ),
        .reset_n        ( reset_n                  ),
        .number         ( { data, 4'b0, r_result } ),
        .digit_enables  ( 4'b1101                  ),
        .out            ( display                  )
    );

endmodule



Топ-модуль с инстанциацией PLL macro от Альтеры для поднятия частоты
http://code.google.com/p/pic32-examples/source/browse/trunk/tedious/011_fpga_coprocessor_ports_3.X/fpga/de0_nano/de0_nano.v

Это хардверная сторона:

module de0_nano
(
    input         clock,
    input  [7: 0] port_e,
    input  [7: 5] port_d_in,
    output [3: 0] port_d_out,
    output [1:12] display,
    output [7: 0] leds
);

    wire reset_n = port_d_in [5];

    wire multiplied_clock;
    wire locked;

    pll50_200 pll50_200_inst
    (
        .areset ( ~ reset_n          ),
        .inclk0 (   clock            ),
        .c0     (   multiplied_clock ),
        .locked (   locked           )
    );

    wire [7: 0] buf_port_e;
    wire [7: 5] buf_port_d_in;
    wire [3: 0] buf_port_d_out;

    ibuf8 ibuf8_inst ( port_e         , buf_port_e     );
    ibuf4 ibuf4_inst ( port_d_in      , buf_port_d_in  );
    obuf4 obuf4_inst ( buf_port_d_out , port_d_out     );

    // Alternatively, we can simply rely
    // on default insertion of I/O cells
    //
    // assign buf_port_e    = port_e;
    // assign buf_port_d_in = port_d_in;
    // assign port_d_out    = buf_port_d_out;

    top top_inst
    (
        .clock      ( multiplied_clock ),
        .port_e     ( buf_port_e       ),
        .port_d_in  ( buf_port_d_in    ),
        .port_d_out ( buf_port_d_out   ),
        .display    ( display          ),
        .leds       ( leds             )
    );

endmodule





Все дружно френдим Евгения Ставинова - http://www.livejournal.com/friends/add.bml?user=outputlogic

Какой путь повышения личной конкурентоспособности является самым эффективным для молодого российского инженера?

Подождать, пока Вексельберг и Медведев договорятся с Цукербергом и следовать их командам
2(11.8%)
Ходить к Макфолу, на митинги Белой Ленты и уважать феминизм Наталии Радуловой
0(0.0%)
Ходить на ланчи с Евгением Ставиновым; взять онлайн-курс на coursera.org от David Wentzlaff
8(47.1%)
Я нашел чудовищную ошибку в панчуловском коде (поясню в комментариях)
2(11.8%)
Из-за бугра плюёте?
5(29.4%)
Subscribe

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 40 comments