1.4.1.1. 同期メモリーブロックの使用
1.4.1.2. サポートされないリセットおよびコントロール条件の回避
1.4.1.3. Read-During-Write動作の確認
1.4.1.4. RAMの推論と実装の制御
1.4.1.5. シングルクロック同期RAM (古いデータでのRead-During-Write動作)
1.4.1.6. シングルクロック同期RAM (新しいデータでのRead-During-Write動作)
1.4.1.7. シンプル・デュアルポート、デュアルクロック同期RAM
1.4.1.8. トゥルー・デュアルポート同期RAM
1.4.1.9. 混合幅デュアルポートRAM
1.4.1.10. バイト・イネーブル信号を備えるRAM
1.4.1.11. 電源投入時の初期のメモリーコンテンツの指定
1.4.4.1. Verilog HDLデュアルクロックFIFOの例
// Copyright 2021 Intel Corporation.
//
// This reference design file is subject licensed to you by the terms and
// conditions of the applicable License Terms and Conditions for Hardware
// Reference Designs and/or Design Examples (either as signed by you or
// found at https://www.altera.com/common/legal/leg-license_agreement.html ).
//
// As stated in the license, you agree to only use this reference design
// solely in conjunction with Intel FPGAs or Intel CPLDs.
//
// THE REFERENCE DESIGN IS PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED
// WARRANTY OF ANY KIND INCLUDING WARRANTIES OF MERCHANTABILITY,
// NONINFRINGEMENT, OR FITNESS FOR A PARTICULAR PURPOSE. Intel does not
// warrant or assume responsibility for the accuracy or completeness of any
// information, links or other items within the Reference Design and any
// accompanying materials.
//
// In the event that you do not agree with such terms and conditions, do not
// use the reference design file.
/////////////////////////////////////////////////////////////////////////////
module dcfifo_example
#(
parameter LOG_DEPTH = 5,
parameter WIDTH = 20,
parameter ALMOST_FULL_VALUE = 30,
parameter ALMOST_EMPTY_VALUE = 2,
parameter NUM_WORDS = 2**LOG_DEPTH - 1,
parameter OVERFLOW_CHECKING = 0, // Overflow checking circuitry is \
using extra area. Use only if you need it
parameter UNDERFLOW_CHECKING = 0 // Underflow checking circuitry is \
using extra area. Use only if you need it
)
(
input aclr,
input wrclk,
input wrreq,
input [WIDTH-1:0] data,
output reg wrempty,
output reg wrfull,
output reg wr_almost_empty,
output reg wr_almost_full,
output [LOG_DEPTH-1:0] wrusedw,
input rdclk,
input rdreq,
output [WIDTH-1:0] q,
output reg rdempty,
output reg rdfull,
output reg rd_almost_empty,
output reg rd_almost_full,
output [LOG_DEPTH-1:0] rdusedw
);
initial begin
if ((LOG_DEPTH > 5) || (LOG_DEPTH < 3))
$error("Invalid parameter value: LOG_DEPTH = %0d; valid range is 2 \
< LOG_DEPTH < 6", LOG_DEPTH);
if ((ALMOST_FULL_VALUE > 2 ** LOG_DEPTH - 1) || (ALMOST_FULL_VALUE < 1))
$error("Incorrect parameter value: ALMOST_FULL_VALUE = %0d; valid \
range is 0 < ALMOST_FULL_VALUE < %0d",
ALMOST_FULL_VALUE, 2 ** LOG_DEPTH);
if ((ALMOST_EMPTY_VALUE > 2 ** LOG_DEPTH - 1) || (ALMOST_EMPTY_VALUE < 1))
$error("Incorrect parameter value: ALMOST_EMPTY_VALUE = %0d; valid \
range is 0 < ALMOST_EMPTY_VALUE < %0d",
ALMOST_EMPTY_VALUE, 2 ** LOG_DEPTH);
if ((NUM_WORDS > 2 ** LOG_DEPTH - 1) || (NUM_WORDS < 1))
$error("Incorrect parameter value: NUM_WORDS = %0d; \
valid range is 0 < NUM_WORDS < %0d",
NUM_WORDS, 2 ** LOG_DEPTH);
end
(* altera_attribute = "-name AUTO_CLOCK_ENABLE_RECOGNITION OFF" *) reg \
[LOG_DEPTH-1:0] write_addr = 0;
(* altera_attribute = "-name AUTO_CLOCK_ENABLE_RECOGNITION OFF" *) reg \
[LOG_DEPTH-1:0] read_addr = 0;
reg [LOG_DEPTH-1:0] wrcapacity = 0;
reg [LOG_DEPTH-1:0] rdcapacity = 0;
wire [LOG_DEPTH-1:0] wrcapacity_w;
wire [LOG_DEPTH-1:0] rdcapacity_w;
wire [LOG_DEPTH-1:0] rd_write_addr;
wire [LOG_DEPTH-1:0] wr_read_addr;
wire wrreq_safe;
wire rdreq_safe;
assign wrreq_safe = OVERFLOW_CHECKING ? wrreq & ~wrfull : wrreq;
assign rdreq_safe = UNDERFLOW_CHECKING ? rdreq & ~rdempty : rdreq;
initial begin
write_addr = 0;
read_addr = 0;
wrempty = 1;
wrfull = 0;
rdempty = 1;
rdfull = 0;
wrcapacity = 0;
rdcapacity = 0;
rd_almost_empty = 1;
rd_almost_full = 0;
wr_almost_empty = 1;
wr_almost_full = 0;
end
// ------------------ Write -------------------------
add_a_b_s0_s1 #(LOG_DEPTH) wr_adder(
.a(write_addr),
.b(~wr_read_addr),
.s0(wrreq_safe),
.s1(1'b1),
.out(wrcapacity_w)
);
always @(posedge wrclk or posedge aclr) begin
if (aclr) begin
write_addr <= 0;
wrcapacity <= 0;
wrempty <= 1;
wrfull <= 0;
wr_almost_full <= 0;
wr_almost_empty <= 1;
end else begin
write_addr <= write_addr + wrreq_safe;
wrcapacity <= wrcapacity_w;
wrempty <= (wrcapacity == 0) && (wrreq == 0);
wrfull <= (wrcapacity == NUM_WORDS) || (wrcapacity == NUM_WORDS - 1) \
&& (wrreq == 1);
wr_almost_empty <=
(wrcapacity < (ALMOST_EMPTY_VALUE-1)) ||
(wrcapacity == (ALMOST_EMPTY_VALUE-1)) && (wrreq == 0);
wr_almost_full <=
(wrcapacity >= ALMOST_FULL_VALUE) ||
(wrcapacity == ALMOST_FULL_VALUE - 1) && (wrreq == 1);
end
end
assign wrusedw = wrcapacity;
// ------------------ Read -------------------------
add_a_b_s0_s1 #(LOG_DEPTH) rd_adder(
.a(rd_write_addr),
.b(~read_addr),
.s0(1'b0),
.s1(~rdreq_safe),
.out(rdcapacity_w)
);
always @(posedge rdclk or posedge aclr) begin
if (aclr) begin
read_addr <= 0;
rdcapacity <= 0;
rdempty <= 1;
rdfull <= 0;
rd_almost_empty <= 1;
rd_almost_full <= 0;
end else begin
read_addr <= read_addr + rdreq_safe;
rdcapacity <= rdcapacity_w;
rdempty <= (rdcapacity == 0) || (rdcapacity == 1) && (rdreq == 1);
rdfull <= (rdcapacity == NUM_WORDS) && (rdreq == 0);
rd_almost_empty <=
(rdcapacity < ALMOST_EMPTY_VALUE) ||
(rdcapacity == ALMOST_EMPTY_VALUE) && (rdreq == 1);
rd_almost_full <=
(rdcapacity > ALMOST_FULL_VALUE) ||
(rdcapacity == ALMOST_FULL_VALUE) && (rdreq == 0);
end
end
assign rdusedw = rdcapacity;
// ---------------- Synchronizers --------------------
wire [LOG_DEPTH-1:0] gray_read_addr;
wire [LOG_DEPTH-1:0] wr_gray_read_addr;
wire [LOG_DEPTH-1:0] gray_write_addr;
wire [LOG_DEPTH-1:0] rd_gray_write_addr;
binary_to_gray #(.WIDTH(LOG_DEPTH)) rd_b2g (.clock(rdclk), .aclr(aclr), \
.din(read_addr), .dout(gray_read_addr));
synchronizer_ff_r2 #(.WIDTH(LOG_DEPTH)) rd2wr (.din_clk(rdclk), .din(gray_read_addr), \
.dout_clk(wrclk), .dout(wr_gray_read_addr));
gray_to_binary #(.WIDTH(LOG_DEPTH)) rd_g2b (.clock(wrclk), .aclr(aclr), \
.din(wr_gray_read_addr), .dout(wr_read_addr));
binary_to_gray #(.WIDTH(LOG_DEPTH)) wr_b2g (.clock(wrclk), .aclr(aclr), .din(write_addr), \
.dout(gray_write_addr));
synchronizer_ff_r2 #(.WIDTH(LOG_DEPTH)) wr2rd (.din_clk(wrclk), .din(gray_write_addr), \
.dout_clk(rdclk), .dout(rd_gray_write_addr));
gray_to_binary #(.WIDTH(LOG_DEPTH)) wr_g2b (.clock(rdclk), .aclr(aclr), \
.din(rd_gray_write_addr), .dout(rd_write_addr));
// ------------------ MLAB ---------------------------
generic_mlab_dc #(.WIDTH(WIDTH), .ADDR_WIDTH(LOG_DEPTH)) mlab_inst (
.rclk(rdclk),
.wclk(wrclk),
.din(data),
.waddr(write_addr),
.we(1'b1),
.re(1'b1),
.raddr(read_addr),
.dout(q)
);
endmodule
module add_a_b_s0_s1 #(
parameter SIZE = 5
)(
input [SIZE-1:0] a,
input [SIZE-1:0] b,
input s0,
input s1,
output [SIZE-1:0] out
);
wire [SIZE:0] left;
wire [SIZE:0] right;
wire temp;
assign left = {a ^ b, s0};
assign right = {a[SIZE-2:0] & b[SIZE-2:0], s1, s0};
assign {out, temp} = left + right;
endmodule
module binary_to_gray #(
parameter WIDTH = 5
) (
input clock,
input aclr,
input [WIDTH-1:0] din,
output reg [WIDTH-1:0] dout
);
always @(posedge clock or posedge aclr) begin
if (aclr)
dout <= 0;
else
dout <= din ^ (din >> 1);
end
endmodule
module gray_to_binary #(
parameter WIDTH = 5
) (
input clock,
input aclr,
input [WIDTH-1:0] din,
output reg [WIDTH-1:0] dout
);
wire [WIDTH-1:0] dout_w;
genvar i;
generate
for (i = 0; i < WIDTH; i=i+1) begin : loop
assign dout_w[i] = ^(din[WIDTH-1:i]);
end
endgenerate
always @(posedge clock or posedge aclr) begin
if (aclr)
dout <= 0;
else
dout <= dout_w;
end
endmodule
(* altera_attribute = "-name SYNCHRONIZER_IDENTIFICATION OFF" *)
module generic_mlab_dc #(
parameter WIDTH = 8,
parameter ADDR_WIDTH = 5
)(
input rclk,
input wclk,
input [WIDTH-1:0] din,
input [ADDR_WIDTH-1:0] waddr,
input we,
input re,
input [ADDR_WIDTH-1:0] raddr,
output [WIDTH-1:0] dout
);
localparam DEPTH = 1 << ADDR_WIDTH;
(* ramstyle = "mlab" *) reg [WIDTH-1:0] mem[0:DEPTH-1];
reg [WIDTH-1:0] dout_r;
always @(posedge wclk) begin
if (we)
mem[waddr] <= din;
end
always @(posedge rclk) begin
if (re)
dout_r <= mem[raddr];
end
assign dout = dout_r;
endmodule
module synchronizer_ff_r2 #(
parameter WIDTH = 8
)(
input din_clk,
input [WIDTH-1:0] din,
input dout_clk,
output [WIDTH-1:0] dout
);
reg [WIDTH-1:0] ff_launch = {WIDTH {1'b0}}
/* synthesis preserve dont_replicate */;
always @(posedge din_clk) begin
ff_launch <= din;
end
reg [WIDTH-1:0] ff_meta = {WIDTH {1'b0}}
/* synthesis preserve dont_replicate */;
always @(posedge dout_clk) begin
ff_meta <= ff_launch;
end
reg [WIDTH-1:0] ff_sync = {WIDTH {1'b0}}
/* synthesis preserve dont_replicate */;
always @(posedge dout_clk) begin
ff_sync <= ff_meta;
end
assign dout = ff_sync;
endmodule