Changes
Page history
move pages to top directory
authored
Oct 23, 2018
by
Toru Koizumi
Show whitespace changes
Inline
Side-by-side
FPGARAM.md
0 → 100644
View page @
48aa03b2
RAM の書き方
============
## RAM の種類
FPGA 上で RAM を構成する方法には、フリップフロップ、分散RAM 、ブロックRAM の三種類があります。
作り方によって回路面積や読み出しのタイミングなどが異なりますが、フリップフロップは回路面積を大きく消費するため、基本的には 分散RAM か ブロックRAM を使うようにしましょう。
分散RAM と ブロックRAM の違いは、簡単に言ってしまえば、あらかじめ用意されている RAM を使うのが ブロックRAM 、LUT を用いて構成されるのが 分散RAM です。
回路面積を消費しないのは ブロックRAM ですが、その分すこし制約がかかります。
## 分散RAM
1 read / 1 write の 分散RAM の記述例です。
重要なのは、
**書き込みのタイミングをクロックと同期する**
ということです。
```
verilog
module
ram
(
clk
,
we
,
r_addr
,
r_data
,
w_addr
,
w_data
);
input
clk
,
we
;
input
[
4
:
0
]
r_addr
,
w_addr
;
input
[
31
:
0
]
w_data
;
output
[
31
:
0
]
r_data
;
reg
[
31
:
0
]
mem
[
0
:
31
];
//32bitのレジスタが32個(アドレスは5bit)
always
@
(
posedge
clk
)
begin
if
(
we
)
mem
[
w_addr
]
<=
w_data
;
//クロックと同期して書き込まれる
end
assign
r_data
=
mem
[
r_addr
];
endmodule
```
同時に読める数(read port 数)を増やすのも難しくはありません。単に入出力の信号線を増やし、
`assign`
文を複数にするだけです。
同時に書ける数(write port 数)を増やすのも同様であり、記述上は[^1]難しくありません。当たり前ですが、同じ場所に複数同時に書き込んだりするとおかしなことになります。
[
^1
]:
実際にどういった回路が組みあがるか、という話になると難しいですが、その辺は論理合成ツールが頑張ってくれるので気にする必要はありません。
## ブロックRAM
1 read / 1 write の ブロックRAM の記述例です。
重要なのは、
**書き込みのタイミングと読み出しアドレスをそれぞれクロックと同期する**
ということです。
```
verilog
module
ram
(
clk
,
we
,
r_addr
,
r_data
,
w_addr
,
w_data
);
input
clk
,
we
;
input
[
4
:
0
]
r_addr
,
w_addr
;
input
[
31
:
0
]
w_data
;
output
[
31
:
0
]
r_data
;
reg
[
4
:
0
]
addr_reg
;
reg
[
31
:
0
]
mem
[
0
:
31
];
always
@
(
posedge
clk
)
begin
if
(
we
)
mem
[
w_addr
]
<=
w_data
;
//書き込みのタイミングを同期
addr_reg
<=
r_addr
;
//読み出しアドレスを同期
end
assign
r_data
=
mem
[
addr_reg
];
endmodule
```
port 数の増やし方は、分散RAM の時と同様です。
## RAM の初期化
RAM の初期化は、モジュール内に次の記述をすることで行うことができます(もちろん、パスは適宜読み替えてください)。
```
verilog
initial
$
readmemh
(
"/home/username/workspace/test.hex"
,
mem
)
```
`$readmemh`
の引数には初期化したいデータが書かれた
**テキストファイル**
へのパスを記述します(バイナリデータではありません。十六進数で記述したテキストデータです)。
```
verilog
0
C00000000000000
08_01_04_00
//アンダーバーを入れてもOK
```
`readmemh`
の二進数版である
`readmemb`
もあります。この場合、参照するファイルには
```
verilog
00001100000000000000000000000000
00000100000000010000010000000000
00000100000000100000000001001000
000001_00000_00011_0000000001100101
```
などと記述します。
次のような記述も可能です。
```
verilog
integer
i
;
initial
begin
for
(
i
=
0
;
i
<
32
;
i
=
i
+
1
)
mem
[
i
]
=
0
;
end
```
```
verilog
initial
begin
mem
[
0
]
=
32'h12345678
;
mem
[
1
]
=
32'h87654321
;
// ...
end
```
今回の実験ではプログラムをビルドすると、ICache と DCache のそれぞれの初期化データとして
`code.hex`
、
`data.hex`
が生成されるようになっています。
従って、ICache と DCache それぞれで
`readmemh`
を用いて
`.hex`
を読み込んでください。
## ROM の記述
ROM の場合も、write 線がないだけで RAM と同様です。すなわち、読み出しを同期すれば ブロックRAM で構成されます。
```
verilog
module
rom
(
clk
,
r_addr
,
r_data
);
input
clk
;
input
[
4
:
0
]
r_addr
;
output
[
31
:
0
]
r_data
;
reg
[
4
:
0
]
addr_reg
;
reg
[
31
:
0
]
mem
[
0
:
31
]
always
@
(
posedge
clk
)
begin
addr_reg
<=
r_addr
;
//読み出しアドレスを同期
end
assign
r_data
=
mem
[
addr_reg
];
endmodule
```
---