Я хочу сделать повышающий счетчик с возможностью вывода (при высоком значении счетчик должен подсчитываться при каждом такте, в противном случае он сохраняет свое предыдущее значение). Чтобы добиться видимых результатов на моей плате Altera TerASIC, я использовал ее встроенный тактовый генератор и встроил в Verilog модуль делителя тактовой частоты, чтобы подать на мой повышающий счетчик тактовый сигнал с гораздо более подходящей частотой. Кроме того, я создал шестнадцатеричный модуль, который подключил к выходу моего обратного счетчика, чтобы иметь возможность видеть выходные значения в виде цифр. Проблема в том, что я не знаю, почему выходные данные увеличиваются на 2 за каждый такт (вместо 1, как ожидалось) при запуске проекта на плате TeraASIC. Я предоставляю весь код ниже, так как не знаю, откуда возникла проблема. Хотя я считаю, что с шестнадцатеричным модулем все в порядке. Проблема возникает либо внутри блока счетчика, либо внутри блока делителя. Кроме того, я сделал небольшой тестовый стенд, результаты которого необычны, поскольку подтверждают, что схема работает нормально. В нижней части этого поста я подробно рассказал о тестовом стенде. Тем не менее, интересно, что если я заменю else if из счетчика на простое else, которое не учитывает сигналы en и d, я получу полностью функциональную конструкцию, простой повышающий счетчик, который увеличивает свое значение после каждого фронта тактовой частоты. . Я не знаю, почему это происходит. Возможно, настоящая проблема скрыта именно там. Я поместил комментарий в эту область кода, чтобы сделать ее более заметной.
module counter(
input clk,
input rst_b,
input en,
input [2:0] d,
output [6:0] digit
);
wire clk_d;
reg [2:0] q;
divider i0(.clk(clk),.rst_b(rst_b),.clk_d(clk_d));
decoder i1(.binary(q),.digit(digit));
always @(posedge clk_d, negedge rst_b) begin
if (rst_b == 1'b0)
q <= 3'b000;
else if (en)//when it was only else q<=q+en; it went fine...why???
if (q == d)
q <= 3'b000;
else
q <= q + en;//increment by 2 instead of 1
end
endmodule
module divider(
input clk,
input rst_b,
output clk_d
);
reg [24:0] q;
always @(posedge clk) begin
if (rst_b == 1'b0)
q <= 25'b0;
else
q <= q-1;
end
assign clk_d = (q == 25'b0);
endmodule
module decoder(
input [2:0] binary,
output reg [6:0] digit
);
always @ * begin
case (binary)
4'h0: digit = ~7'b0111111;
4'h1: digit = ~7'b0000110;
4'h2: digit = ~7'b1011011;
4'h3: digit = ~7'b1001111;
4'h4: digit = ~7'b1100110;
4'h5: digit = ~7'b1101101;
4'h6: digit = ~7'b1111101;
4'h7: digit = ~7'b0000111;
default : digit = ~7'b1110001;
endcase
end
endmodule
У меня есть небольшой тестовый стенд, который поразительно доказывает, что, по крайней мере теоретически, мой модуль работает нормально:
module counter_tb;
reg clk, rst_b, en;
reg [2:0] d;
wire [6:0] digit;
counter i0( .clk(clk),
.rst_b(rst_b),
.en(en),
.d(d),
.digit(digit)
);
always begin
#1 clk = ~clk;
end
initial begin
clk = 1'b0;
en = 1'b1;
d = 3'b111;
rst_b = 1'b0;
#3 rst_b = 1'b1;
end
endmodule
Я не знаю точно, в чем ваша проблема или какое решение, однако вы используете практику проектирования, которая, как правило, не работает в потоке синтеза (нацеленном на аппаратное обеспечение) для создания часов. Если это работает в одной сборке, то может не работать в следующей. Небольшая дополнительная задержка (например, добавление разрешения) приведет к совершенно другим результатам в аппаратном обеспечении.
Эта практика обманчива, потому что вы можете написать что-то, что в моделировании будет вести себя так, как вы хотите, но не будет вести себя так, как ожидается, в рабочем процессе синтеза/аппаратного обеспечения. Симулятор Verilog обычно не моделирует задержки (моделирование на основе задержек возможно, но все равно не решает проблемы), поэтому необходимо использовать определенные передовые методы проектирования, чтобы результаты аппаратного обеспечения согласовывались с моделированием.
Как правило, вы не можете создавать часы и использовать их в качестве часов для других триггеров, используя простые делители триггеров в физической FPGA. Есть два надежных варианта получения поведения, связанного с генерацией более медленных часов.
Эта ссылка объясняет больше и хорошо написана, я не мог бы объяснить это лучше
Делители часов с использованием триггеров в RTL на FPGA – большое НЕТ!
без написания статьи.
Это будет отдельный и новый вопрос и ответ
«Как мне создать делитель тактовой частоты в FPGA, который может использовать аппаратное обеспечение в рабочих процессах синтеза»
Я бы избавился от триггерного делителя assign clk_d = (q == 25'b0);
и связанной с ним логики и использовал одно из двух решений, которые я упомянул и которые упомянуты по предоставленной ссылке.
Кроме того, если вы развертываете код RTL в лаборатории без моделирования с помощью тестового стенда, вы часто будете видеть черный ящик с надписью «это не работает».
Я бы использовал подход с включением тактовой частоты, если только вам не нравится углубляться в работу с поставщиками, встроенными в IP.
Очень хороший подход. Действительно, как я добавил в своем последнем редактировании, я столкнулся с таким поведением только при реализации на моей физической плате, поскольку тестовый стенд выглядел нормально.