Простой генератор целочисленных делителей частоты на D

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

Для решения проблемы можно применить достаточно простой модуль на Verilog, который делит входную частоту на некоторое целое число. Конечно, при этом можно все сделать вручную, рассчитав делитель для частоты с помощью калькулятора, но порой требуется множество модулей делителей, которые никак не связаны между собой — и вот тут нам может помочь D: используя простой и понятный синтаксис можно программным путем сгенерировать нужный модуль, практически не обращаясь к Verilog.

Для создания модуля целочисленного деления я написал следующую небольшую утилиту, которую очень удобно запускать из терминала Linux c посощью rdmd:

import std.conv;
import std.stdio;
import std.string;

auto generateDivider(int[] frequencies)
{
	enum VERILOG_CODE = `
module frequency_divider(
	input clock_in,
	output clock_out	
);
	reg[27:0] counter = 28'd0;
	parameter DIVISOR = %1$s;
	always @(posedge clock_in)
		begin
 			counter <= counter + 28'd1;
 			if(counter >= (DIVISOR - 1))
  					counter <= 28'd0;
		end
	assign clock_out = (counter < DIVISOR / 2) ? 1'b0 : 1'b1;

endmodule
`;
	auto inputClock = frequencies[0];
	auto outputClock = frequencies[1];
	return VERILOG_CODE.format(inputClock / outputClock);
}

void main(string[] args)
{
	if (args.length < 3)
	{
		writeln(`usage: frequency <input_frequency (in Hz)> <outpit_frequency (in Hz)>`);		
	}
	else
	{
		import std.algorithm;
		import std.range;

		alias toInt = to!int;
		
		args[1..$]
			.map!toInt
			.array
			.generateDivider
			.writeln;
			
	}
}

Утилита принимает на вход два параметра: исходную частоту, которая равна частоте тактового генератора, либо частоте выходящей из некоторого иного модуля; и выходную частоту, которую требуется получить с помощью делителя. Обе частоты измеряются в герцах, что позволяет получать довольно широкий диапазон частот с помощью простого счетчика, реализованного с помощью кода на Verilog.

Соответственно, результатом работы этой скромной утилитки будет простой код модуля на Verilog, который можно вставить в любую среду для разработки под ПЛИС.

Вот к примеру, код делителя сгенерированный для того, чтобы из 25 МГц получить 7 Гц:

module frequency_divider(
    input clock_in,
    output clock_out
);
    reg[27:0] counter = 28'd0;
    parameter DIVISOR = 3571428;
    always @(posedge clock_in)
        begin
            counter <= counter + 28'd1;
            if(counter >= (DIVISOR - 1))
                    counter <= 28'd0;
        end
    assign clock_out = (counter < DIVISOR / 2) ? 1'b0 : 1'b1;

endmodule

Использовать можно в том числе и в Icestudio, для чего необходимо избавится от декларации модуля (ключевые слова module и endmodule, а также связанные с ними имена).

Добавить комментарий