組み込みRAMーその1

またしてもこの本でVerilogだ。

FPGA ボードで学ぶ組込みシステム開発入門 ?Altera編?

FPGA ボードで学ぶ組込みシステム開発入門 ?Altera編?

今回は7-2節で出てくる組み込みRAMの検証だ。


まずはMega WizardでRAMを作る、主な設定は以下の通り。

  • RAM 2 port
  • 1 port read / 1 port write
  • 8bits/word x 16words、memory block typeはautoで選択
  • sigle clock, read enableはなし
  • read portのregisterは外す(出力はクロック非同期)

後はすべてデフォルトで作成する。
出来上がったRAMの宣言はこんな感じになる。

module eram (
	clock,
	data,
	rdaddress,
	wraddress,
	wren,
	q);

	input	  clock;
	input	[7:0]  data;
	input	[3:0]  rdaddress;
	input	[3:0]  wraddress;
	input	  wren;
	output	[7:0]  q;

テストしてみよう。
以下のようなRAMの書き込み、読み出しをするモジュールを作る。

  • 10バイト目(アドレス0x00から0x09)までそのアドレス値を書く
  • それを10バイト目(アドレス0x00から0x09)まで読み出す
module eram_wr_test(
	input wire in_clk,
	input wire in_reset,
	output reg [2:0] state_machine,
	output wire f_counter_write_expired,
	output wire f_counter_read_expired,
	output reg [3:0] _4bit_counter_write,
	output reg [3:0] _4bit_counter_read,
	output wire [7:0] read_buffer,
	output wire [7:0] sram_read_out);
	//
	// state machine
	//
	parameter INIT = 3'b000;
	parameter WRITE = 3'b001;
	parameter HOLD = 3'b010;
	parameter READ = 3'b011;
	parameter STOP = 3'b100;
	//
	always @(posedge in_clk, posedge in_reset)
	begin
		if (in_reset)
			state_machine <= INIT;
		else
		case (state_machine)
			INIT:
					state_machine <= WRITE;
			WRITE:
				if (f_counter_write_expired)
					state_machine <= HOLD;
				else
					state_machine <= WRITE;
			HOLD:
					state_machine <= READ;
			READ:
				if (f_counter_read_expired)
					state_machine <= STOP;
				else
					state_machine <= READ;
			STOP:
					state_machine <= STOP;			
		endcase
	end
	//
	// write counter
	//
	assign f_counter_write_expired = (_4bit_counter_write == 4'd9)? 1'b1: 1'b0;
	//
	always @(negedge in_clk, posedge in_reset)
	begin
		if (in_reset)
			_4bit_counter_write <= 4'd0;
		else if (state_machine == WRITE)
		begin
			if (f_counter_write_expired)
			begin
				_4bit_counter_write <= 4'd0;
			end
			else
			begin
				_4bit_counter_write <= _4bit_counter_write +4'd1;
			end
		end
	end
	//
	// memory writer
	//
	reg [7:0] _8bit_16word_ram [0:15];
	//
	integer counter_ram_clear;
	always @(posedge in_clk, posedge in_reset)
	begin
		if (in_reset)
		begin
			for (counter_ram_clear = 0; counter_ram_clear < 16; counter_ram_clear = counter_ram_clear + 1)
			begin
				_8bit_16word_ram[counter_ram_clear] <= 8'h0;
			end
		end
		else if (state_machine == WRITE)
			_8bit_16word_ram[_4bit_counter_write] = {4'b0000, _4bit_counter_write};
	end
	//
	// read counter
	//
	assign f_counter_read_expired = (_4bit_counter_read == 4'd9)? 1'b1: 1'b0;
	assign read_buffer = (state_machine == READ)? _8bit_16word_ram[_4bit_counter_read]: 8'h00;
	//	
	always @(negedge in_clk, posedge in_reset)
	begin
		if (in_reset)
			_4bit_counter_read <= 4'd0;
		else if (state_machine == READ)
		begin
			if (f_counter_read_expired)
				_4bit_counter_read <= 4'd0;
			else
				_4bit_counter_read <= _4bit_counter_read + 4'd1;
		end
	end
	//
	// ERAM module
	//
	//
	wire write_enable;
	assign write_enable = (state_machine == WRITE)? 1'b1: 1'b0;
	//
	eram ERAM(
		.clock(in_clk),
		.data({4'b0000, _4bit_counter_write}),
		.rdaddress(_4bit_counter_read),
		.wraddress(_4bit_counter_write),
		.wren(write_enable),
		.q(sram_read_out));
endmodule

比較として、同じような8bit幅16wordのレジスタを作り、同時に読み書きする。
こちらがRTLシミュレーションの結果。

一番下2つのうち、上がレジスタの読み出し結果、下が組み込みRAMの読み出し結果だ。
レジスタはアドレスが変われば、読み出し値が変わる、ただのラッチなので当たり前か。
一方組み込みRAMの方はアドレスがセットされて次のクロック立ち上がりでデータが読み出される。