Pull to refresh

Verilog. Обертки RAM и зачем это нужно

Electronics for beginners
Sandbox
Дело в том, что моему знакомству с FPGA два года. В студенческие годы, читая code examples от Altera и Xilinx, я мало уделял внимания описанию RAM и ROM, ведь в этом не было необходимости. Я знал, что существует FIFO, но даже не догадывался, зачем оно мне нужно. Так я защитил диплом, сделав свой проект «в лоб».

Работу я нашел благодаря своим «знаниям» в области FPGA. Тут же вылезли проблемы, о которых я не подозревал: существующие проекты занимали под 90% логических элементов, а моей работой было разместить в проектах цифровые фильтры. Понятно, что «в лоб» решить эту проблему было невозможно. Переписать существующий код? Помогло, но не сильно. И только тогда я понял, как можно играть с RAM, чтобы решить поставленные задачи.

Внимание! Здесь не будут моргать светодиоды. Вместо этого будет рассмотрена реализация сдвигового регистра в виде обертки для M4K. Данная публикация предполагает минимальное знакомство с FPGA и языком Verilog.

Начнем с того, что сделав «в лоб» необходимый фильтр в отдельном проекте стало понятно, где в нем тонкое место. Им оказался сдвиговый регистр длины 444*16 бит (444 — порядок фильтра, 16 бит — размерность слова). С этим нужно что-то было делать. Мысль пришла к тому, что сдвиг — операция тривиальная. Достать текущее значение регистра на шаге N и записать туда значение регистра, взятого на шаге N-1. Перечитав code examples я нашел, как это сделать с помощью RAM:

module pip
#(parameter DATA_WIDTH=16, parameter ADDR_WIDTH=9)
	(
	input [(DATA_WIDTH-1):0] data,
	input [(ADDR_WIDTH-1):0] read_addr, write_addr,
	input we, clk,
	output reg [(DATA_WIDTH-1):0] q
	);

(*ramstyle = "M4K"*)reg [DATA_WIDTH-1:0] ram[2**ADDR_WIDTH-1:0];

always @ (posedge clk)
begin
	q <= ram[read_addr];
	if (we)
		ram[write_addr] <= data;
end

endmodule


Это взято прямо из examples, изменились только параметры. Теперь остается заставить этот RAM работать, как было описано выше. Для этого было написано то, что я назвал оберткой RAM. Простенький конечный автомат:

module upr
#(parameter DATA_WIDTH = 16, parameter ADDR_WIDTH = 9)
	(
	input wire							clk,
	input wire							en,
	input wire	[ (DATA_WIDTH-1) :  0 ]	ram_upr,
	input wire 	[ (DATA_WIDTH-1) :  0 ]	data_in,

	output wire	[ (DATA_WIDTH-1) :  0 ]	upr_ram,
	output wire							we_ram,
	output wire	[ (ADDR_WIDTH-1) :  0 ]	adr_out
	);

assign upr_ram = ram;
assign we_ram = r_we;
assign adr_out = r_adr;

reg [  2 :  0 ]	r_state = state0;
localparam		state0 = 3'b001,
				state1 = 3'b010,
				state2 = 3'b100;

reg [ (ADDR_WIDTH-1) :  0 ]	r_adr = {ADDR_WIDTH{1'b0}};

reg	[ (DATA_WIDTH-1) :  0 ]	ram = {DATA_WIDTH{1'b0}};
reg							r_we = 1'b0;

always @(posedge clk)
if(en)
begin
	case(r_state)
		state0:
			r_state <= state1;

		state1:
			r_state <= state2;

		state2:
			r_state <= state1;

	endcase
end

always @(posedge clk)
case(r_state)
	state0:
		begin
			r_we <= 1'b0;
			r_adr <= {ADDR_WIDTH{1'b0}};
			ram <= data_in;
		end

	state1:
		begin
			r_we <= 1'b1;
			if(r_adr == {ADDR_WIDTH{1'b0}})
				ram <= data_in;
			else
				ram <= ram_upr;
		end

	state2:
		begin
			r_adr <= r_adr + 1'b1;
			r_we <= 1'b0;
		end

endcase

endmodule


Работает в два этапа + одно состояние, которое может использоваться при сбросе. Конечный автомат предельно прост — никаких условий перехода, только фронт тактового сигнала. На первом шаге (State1) идет захват данных, либо предыдущего выходного значения с RAM. Получилась такая вот обратная связь. Ко второму шагу устанавливается сигнал записи в единицу и RAM захватит то, что нужно.

У этого подхода есть существенный минус — сдвиг занимает 2 такта, но и эту проблему можно легко решить. Другой существенный минус — невозможно за один такт «вытащить» хотя бы два значения из сдвигового регистра. Это значит, что сверточный кодер на таком уже не сделаеш. Плюсом такого подхода является экономия логических элементов (LE или Slice) за счет памяти.

Как решить проблему 2 тактов и, что интереснее, как сделать на основе этого полностью параметризованный цифровой КИХ фильтр я расскажу, если кому-нибудь это будет интересно.
Tags:verilogfpgafsm
Hubs: Electronics for beginners
Total votes 21: ↑19 and ↓2 +17
Views13.8K

Popular right now

Top of the last 24 hours