... | @@ -27,7 +27,7 @@ FPGA 上で RAM を構成する方法には、フリップフロップ、分散R |
... | @@ -27,7 +27,7 @@ FPGA 上で RAM を構成する方法には、フリップフロップ、分散R |
|
|
|
|
|
## 分散RAM
|
|
## 分散RAM
|
|
|
|
|
|
1 read / 1 write の 分散RAM の記述例です。
|
|
1 read + 1 write の 分散RAM の記述例です。
|
|
|
|
|
|
重要なのは、**書き込みのタイミングをクロックと同期する**ということです。
|
|
重要なのは、**書き込みのタイミングをクロックと同期する**ということです。
|
|
|
|
|
... | @@ -49,27 +49,25 @@ FPGA 上で RAM を構成する方法には、フリップフロップ、分散R |
... | @@ -49,27 +49,25 @@ FPGA 上で RAM を構成する方法には、フリップフロップ、分散R |
|
|
|
|
|
## ブロックRAM
|
|
## ブロックRAM
|
|
|
|
|
|
1 read / 1 write の ブロックRAM の記述例です。
|
|
1 read + 1 write の ブロックRAM の記述例です。
|
|
|
|
|
|
重要なのは、**書き込みのタイミングと読み出しアドレスをそれぞれクロックと同期する**ということです。
|
|
重要なのは、**書き込みのタイミングと読み出しのタイミングをそれぞれクロックと同期する**ということです。
|
|
|
|
|
|
```verilog
|
|
```verilog
|
|
module ram(clk, we, r_addr, r_data, w_addr, w_data);
|
|
module ram(clk, we, r_addr, r_data, w_addr, w_data);
|
|
input clk, we;
|
|
input clk, we;
|
|
input [4:0] r_addr, w_addr;
|
|
input [4:0] r_addr, w_addr;
|
|
input [31:0] w_data;
|
|
input [31:0] w_data;
|
|
output [31:0] r_data;
|
|
output reg [31:0] r_data;
|
|
reg [4:0] addr_reg;
|
|
|
|
reg [31:0] mem [0:31];
|
|
reg [31:0] mem [0:31];
|
|
always @(posedge clk) begin
|
|
always @(posedge clk) begin
|
|
if(we) mem[w_addr] <= w_data; // 書き込みのタイミングを同期
|
|
if(we) mem[w_addr] <= w_data; // 書き込みのタイミングを同期
|
|
addr_reg <= r_addr; //読み出しアドレスを同期
|
|
r_data <= mem[r_addr]; // 読み出しのタイミングを同期
|
|
end
|
|
end
|
|
assign r_data = mem[addr_reg];
|
|
|
|
endmodule
|
|
endmodule
|
|
```
|
|
```
|
|
|
|
|
|
port 数の増やし方は、分散RAM の時と同様ですが、2つまでしか増やせません。
|
|
port 数の増やし方は、分散RAM の時と同様ですが、2つまでしか増やせません(上記例は 1 read + 1 write で2 port 使っているため、これ以上増やせません。2 read にすることや、read と write 兼用の port を二つ設けることは可能です)。
|
|
|
|
|
|
## バイトマスク付きライト
|
|
## バイトマスク付きライト
|
|
|
|
|
... | @@ -82,17 +80,15 @@ port 数の増やし方は、分散RAM の時と同様ですが、2つまでし |
... | @@ -82,17 +80,15 @@ port 数の増やし方は、分散RAM の時と同様ですが、2つまでし |
|
input [3:0] we; // 書き込むバイトは1, 書き込まないでそのままにするバイトは0を指定
|
|
input [3:0] we; // 書き込むバイトは1, 書き込まないでそのままにするバイトは0を指定
|
|
input [4:0] r_addr, w_addr;
|
|
input [4:0] r_addr, w_addr;
|
|
input [31:0] w_data;
|
|
input [31:0] w_data;
|
|
output [31:0] r_data;
|
|
output reg [31:0] r_data;
|
|
reg [4:0] addr_reg;
|
|
|
|
reg [31:0] mem [0:31];
|
|
reg [31:0] mem [0:31];
|
|
always @(posedge clk) begin
|
|
always @(posedge clk) begin
|
|
if(we[0]) mem[w_addr][ 7: 0] <= w_data[ 7: 0];
|
|
if(we[0]) mem[w_addr][ 7: 0] <= w_data[ 7: 0];
|
|
if(we[1]) mem[w_addr][15: 8] <= w_data[15: 8];
|
|
if(we[1]) mem[w_addr][15: 8] <= w_data[15: 8];
|
|
if(we[2]) mem[w_addr][23:16] <= w_data[23:16];
|
|
if(we[2]) mem[w_addr][23:16] <= w_data[23:16];
|
|
if(we[3]) mem[w_addr][31:24] <= w_data[31:24];
|
|
if(we[3]) mem[w_addr][31:24] <= w_data[31:24];
|
|
addr_reg <= r_addr;
|
|
r_data <= mem[r_addr];
|
|
end
|
|
end
|
|
assign r_data = mem[addr_reg];
|
|
|
|
endmodule
|
|
endmodule
|
|
```
|
|
```
|
|
|
|
|
... | @@ -146,18 +142,16 @@ RAM の初期化は、モジュール内に次の記述をすることで行う |
... | @@ -146,18 +142,16 @@ RAM の初期化は、モジュール内に次の記述をすることで行う |
|
|
|
|
|
## ROM の記述
|
|
## ROM の記述
|
|
|
|
|
|
ROM の場合も、write 線がないだけで RAM と同様です。すなわち、読み出しを同期すれば ブロックRAM で構成されます。
|
|
ROM の場合も、write 線がないだけで RAM と同様です。すなわち、読み出しタイミングを同期すれば ブロックRAM で構成されます。
|
|
|
|
|
|
```verilog
|
|
```verilog
|
|
module rom(clk, r_addr, r_data);
|
|
module rom(clk, r_addr, r_data);
|
|
input clk;
|
|
input clk;
|
|
input [4:0] r_addr;
|
|
input [4:0] r_addr;
|
|
output [31:0] r_data;
|
|
output reg [31:0] r_data;
|
|
reg [4:0] addr_reg;
|
|
|
|
reg [31:0] mem [0:31]
|
|
reg [31:0] mem [0:31]
|
|
always @(posedge clk) begin
|
|
always @(posedge clk) begin
|
|
addr_reg <= r_addr; //読み出しアドレスを同期
|
|
r_data <= mem[r_addr]; // 読み出しタイミングを同期
|
|
end
|
|
end
|
|
assign r_data = mem[addr_reg];
|
|
|
|
endmodule
|
|
endmodule
|
|
``` |
|
``` |