Несколько конфликтующих драйверов для reg назначены только в одном блоке - PullRequest
0 голосов
/ 30 сентября 2019

Я работаю над простым модулем синхронизации видеосигнала в Verilog, как учебный проект. Из предыдущего исследования я понял, что каждый reg должен назначаться только из одного блока always, поэтому я организовал свою систему в два блока конечного автомата, а затем один блок для заполнения выходных регистров, как показано ниже:

module video_timing
(
    input wire reset,
    input wire clk,

    output reg [15:0] x,
    output reg [15:0] y,
    output reg hsync,
    output reg vsync,
    output reg visible
);

    // State constants for our two timing state machines (one horizontal, one vertical)
    `define VIDEO_SYNC       2'd0
    `define VIDEO_BACKPORCH  2'd1
    `define VIDEO_ACTIVE     2'd2
    `define VIDEO_FRONTPORCH 2'd3

    // These settings are for 720p, assuming clk is running at 74.25 MHz
    `define VIDEO_H_SYNC_PIXELS   16'd40
    `define VIDEO_H_BP_PIXELS     16'd220
    `define VIDEO_H_ACTIVE_PIXELS 16'd1280
    `define VIDEO_H_FP_PIXELS     16'd110
    `define VIDEO_H_SYNC_ACTIVE   1'b1
    `define VIDEO_V_SYNC_LINES    16'd5
    `define VIDEO_V_BP_LINES      16'd20
    `define VIDEO_V_ACTIVE_LINES  16'd720
    `define VIDEO_V_FP_LINES      16'd5
    `define VIDEO_V_SYNC_ACTIVE   1'b1

    reg [1:0] state_h;
    reg [15:0] count_h; // 1-based so we will stop when count_h is the total pixels for the current state
    reg inc_v = 1'b0;
    reg [1:0] state_v;
    reg [15:0] count_v; // 1-based so we will stop when count_v is the total lines for the current state

    // Change outputs on clock.
    // (These update one clock step behind everything else below, but that's
    //  okay because the lengths of all the periods are still correct.)
    always @(posedge clk) begin
        if (reset == 1'b1) begin
            hsync   <= ~`VIDEO_H_SYNC_ACTIVE;
            vsync   <= ~`VIDEO_V_SYNC_ACTIVE;
            visible <= 1'b0;
            x       <= 16'd0;
            y       <= 16'd0;
        end else begin
            hsync   <= (state_h == `VIDEO_SYNC) ^ (~`VIDEO_H_SYNC_ACTIVE);
            vsync   <= (state_v == `VIDEO_SYNC) ^ (~`VIDEO_V_SYNC_ACTIVE);
            visible <= (state_h == `VIDEO_ACTIVE) && (state_v == `VIDEO_ACTIVE);
            x       <= count_h - 1;
            y       <= count_v - 1;
         end
    end

    // Horizontal state machine
    always @(posedge clk) begin
        if (reset == 1'b1) begin
            count_h <= 16'b1;
            state_h <= `VIDEO_FRONTPORCH;
        end else begin
            inc_v <= 0;
            count_h <= count_h + 16'd1;

            case (state_h)
                `VIDEO_SYNC: begin
                    if (count_h == `VIDEO_H_SYNC_PIXELS) begin
                        state_h <= `VIDEO_BACKPORCH;
                        count_h <= 16'b1;
                    end
                end
                `VIDEO_BACKPORCH: begin
                    if (count_h == `VIDEO_H_BP_PIXELS) begin
                        state_h <= `VIDEO_ACTIVE;
                        count_h <= 16'b1;
                    end
                end
                `VIDEO_ACTIVE: begin
                    if (count_h == `VIDEO_H_ACTIVE_PIXELS) begin
                        state_h <= `VIDEO_FRONTPORCH;
                        count_h <= 16'b1;
                    end
                end
                `VIDEO_FRONTPORCH: begin
                    if (count_h == `VIDEO_H_FP_PIXELS) begin
                        state_h <= `VIDEO_SYNC;
                        count_h <= 16'b1;
                        inc_v <= 1;
                    end
                end
            endcase
        end
    end

    // Vertical state machine
    always @(posedge clk) begin
        if (reset == 1'b1) begin
            count_v <= 16'b1;
            state_v <= `VIDEO_FRONTPORCH;
        end else begin
            if (inc_v) begin
                count_v <= count_v + 16'd1;
                case (state_v)
                    `VIDEO_SYNC: begin
                        if (count_v == `VIDEO_V_SYNC_LINES) begin
                            state_v <= `VIDEO_BACKPORCH;
                            count_v <= 16'b1;
                        end
                    end
                    `VIDEO_BACKPORCH: begin
                        if (count_v == `VIDEO_V_BP_LINES) begin
                            state_v <= `VIDEO_ACTIVE;
                            count_v <= 16'b1;
                        end
                    end
                    `VIDEO_ACTIVE: begin
                        if (count_v == `VIDEO_V_ACTIVE_LINES) begin
                            state_v <= `VIDEO_FRONTPORCH;
                            count_v <= 16'b1;
                        end
                    end
                    `VIDEO_FRONTPORCH: begin
                        if (count_v == `VIDEO_V_FP_LINES) begin
                            state_v <= `VIDEO_SYNC;
                            count_v <= 16'b1;
                        end
                    end
                endcase
            end
        end
    end

endmodule

При попытке синтезировать это с помощью цепочки инструментов IceStorm, yosys предупреждает, что есть несколько драйверов для hsync:

Warning: multiple conflicting drivers for top.\timing.hsync:
    port Q[0] of cell $techmap\timing.$procdff$109 ($adff)
    port Q[0] of cell $techmap\timing.$procdff$110 ($adff)

nextpnr-ice40, а затем происходит сбой по той же проблеме:

ERROR: multiple drivers on net 'P1B4' ($auto$simplemap.cc:496:simplemap_adff$375.Q and $auto$simplemap.cc:496:simplemap_adff$376.Q)
ERROR: Loading design failed.

Я попытался решить несколько разных задач и сделал несколько замечаний:

  • Если я изменю назначение в case (reset) 0:блок (в первом всегда), равный hsync <= 'VIDEO_H_SYNC_ACTIVE, тогда результат является синтезируемым и действительно постоянно утверждает hsync, когда нет сброса, как я ожидаю после внесения этого изменения.
  • Если я удалюhsync <= (state_h == 'VIDEO_SYNC) ^ (~'VIDEO_H_SYNC_ACTIVE) полностью, но сохраняйте hsync <= ~'VIDEO_H_SYNC_ACTIVE во время сброса, тогда результат также может быть синтетическим, и hsync постоянно не утверждается.

(я заменил галочки на ' выше только потому, что backtick является метасимволом Markdown для встроенного дословного текста. Я использую обратные метки для констант в моей реальной программе.)

Это привело меня к выводу, что выражение в правой части hsync <= является проблемой. Но затем я запутался, почему очень похожая следующая строка vsync <= не выдает подобную ошибку:

hsync <= (state_h == `VIDEO_SYNC) ^ (~`VIDEO_H_SYNC_ACTIVE);
vsync <= (state_v == `VIDEO_SYNC) ^ (~`VIDEO_V_SYNC_ACTIVE);

Модуль ведет себя так, как я ожидал при моделировании с iverilog.

Я использую Yosys 0.8 и nextpnr из git sha1 a6a4349. Я также попытался обновить до Yosys 0.9 и получил тот же результат, но я подозреваю, что это моя ошибка, а не в наборе инструментов.

Ответы [ 2 ]

2 голосов
/ 30 сентября 2019

Этот шаблон асинхронного сброса не разрешен стандартом синтеза IEEE (1364.1). Таким образом, можно использовать только оператор if:

IEEE 1364.1 - 5.2.2.1 Edge-sensitive storage device modeling with asynchronous set-reset

0 голосов
/ 01 октября 2019

Другие ответы здесь были важными шагами:

  • Моя реализация сброса изначально была асинхронной и написана так, что не соответствовала стандарту синтеза Verilog.
  • Моя логика условного сброса была написана с использованием switch, а не if (из-за некоторого запутанного совета, который я видел в другом месте).

К сожалению, след там иссяк, потому что после этого timing.v былсинтезировать просто отлично. Оказалось, что проблема на самом деле была в top.v вместо:

    video_timing timing(
        .reset(reset_loc),
        .clk(vga_ck),
        .hsync(vga_hs),
        .vsync(vga_hs),
        .visible(vga_de)
    );

Я случайно назначил vga_hs обоим hsync и vsync. 10

После изменения строки vsync для ссылки на vga_vs проект теперь синтезирует и ведет себя, как и ожидалось.

Извлеченный урок: проблема не всегда в том, гдекомпилятор думает, что это так!

...