論理回路デザイン
|
|




/* **************************** MODULE PREAMBLE ********************************
Copyright (c) 2012, ArchiTek
This document constitutes confidential and proprietary information
of ArchiTek. All rights reserved.
// 基本クロックと4位相のクロックを生成する最上位モジュール*/
// ***************************** MODULE HEADER *********************************
`timescale 1ps / 1ps
module test;
// ************************ PARAMETER DECLARATIONS *****************************
parameter D = 1;
parameter DCLK = 2500;
parameter DCLK2 = DCLK/2;
parameter DCLK4 = DCLK/4;
// ************************** LOCAL DECLARATIONS *******************************
reg clk, clk_n;
reg reset_n;
reg ddr_clk_0, ddr_clk_90, ddr_clk_180, ddr_clk_270;
// ****************************** MODULE BODY **********************************
// -----------------------------------------------------------------------------
initial begin clk=0; forever begin #(DCLK2) clk=~clk; end end
initial begin clk_n=1; forever begin #(DCLK2) clk_n=~clk_n; end end
// -----------------------------------------------------------------------------
initial begin reset_n=0; #D reset_n=0; #(DCLK*3.5) reset_n=1; end
// -----------------------------------------------------------------------------
initial begin ddr_clk_0 =0; #(DCLK4*0) forever begin #(DCLK2) ddr_clk_0 =~ddr_clk_0; end end
initial begin ddr_clk_90 =0; #(DCLK4*1) forever begin #(DCLK2) ddr_clk_90 =~ddr_clk_90; end end
initial begin ddr_clk_180=0; #(DCLK4*2) forever begin #(DCLK2) ddr_clk_180=~ddr_clk_180; end end
initial begin ddr_clk_270=0; #(DCLK4*3) forever begin #(DCLK2) ddr_clk_270=~ddr_clk_270; end end
// -----------------------------------------------------------------------------
top top_0 (
clk, clk_n, reset_n,
ddr_clk_0, ddr_clk_90, ddr_clk_180, ddr_clk_270
);
// ************************** FUNCTIONS and TASKS ******************************
endmodule
// *****************************************************************************
/* **************************** MODULE PREAMBLE ********************************
Copyright (c) 2012, ArchiTek
This document constitutes confidential and proprietary information
of ArchiTek. All rights reserved.
*/
// ***************************** MODULE HEADER *********************************
module top (
clk, clk_n, reset_n,
ddr_clk_0, ddr_clk_90, ddr_clk_180, ddr_clk_270
);
// ************************ PARAMETER DECLARATIONS *****************************
parameter ST = 10000; // Simulation interval
// ***************************** I/O DECLARATIONS ******************************
input clk;
input clk_n;
input reset_n;
input ddr_clk_0;
input ddr_clk_90;
input ddr_clk_180;
input ddr_clk_270;
// ************************** LOCAL DECLARATIONS *******************************
// 通常アクセスマスター信号
wire iReq;
wire iGnt;
wire iRxw;
wire [31:0] iAddr;
wire iWrStrb;
wire iWrAck;
wire [15:0] iWrData;
wire [1:0] iWrMask;
wire iRdStrb;
wire iRdAck;
wire [15:0] iRdData;
// 割り込みアクセスマスター信号
wire pReq;
wire pGnt;
wire [31:0] pAddr;
// sdcモジュールのDDR信号
wire sd_cs_n;
wire sd_ras_n;
wire sd_cas_n;
wire sd_we_n;
wire sd_cke = 1'b1;
wire [2:0] sd_ba;
wire [15:0] sd_addr;
wire sd_odt = 1'b0;
wire sd_reset_n = 1'b1;
wire sd_wdvldt;
wire sd_wdvldd;
wire sd_wdvld = sd_wdvldt | sd_wdvldd;
wire [15:0] sd_wd;
wire [1:0] sd_wdqm;
wire sd_rdvld;
wire [15:0] sd_rd;
// ACタイミングの設定
wire [7:0] reg_pACCW = 8'h18;
wire [7:0] reg_pACCR = 8'h16;
wire [7:0] reg_pCOM = 8'h4f;
wire [4:0] reg_pFAW = 5'h12;
wire [4:0] reg_pRRD = 5'h03;
wire [4:0] reg_dTWR = 5'h0b;
wire [4:0] reg_dTRW = 5'h06;
wire [4:0] reg_dWL = 5'h07;
wire [4:0] reg_dRL = 5'h08;
// I/Oから見たDDR信号
wire ddr_cs_n;
wire ddr_ras_n;
wire ddr_cas_n;
wire ddr_we_n;
wire ddr_cke;
wire [2:0] ddr_ba;
wire [15:0] ddr_addr;
wire ddr_odt;
wire ddr_reset_n;
wire [7:0] ddr_dq;
wire ddr_dqm;
wire ddr_dqs_p;
wire ddr_dqs_n;
wire ddr_rdqs_n;
wire [7:0] ddr_din;
wire [7:0] ddr_dout;
wire [7:0] ddr_oe;
wire ddr_dqsout;
wire ddr_dqsin;
wire ddr_dqs_poe;
wire ddr_dqs_noe;
wire ddr_dqs_pbus;
wire ddr_clk_p;
wire ddr_clk_n;
// シミュレーション用変数
reg [1:0] rst;
reg reset;
reg [31:0] tsc;
reg ts_req;
wire ts_gnt;
reg [31:0] ts_addr;
reg ts_hold;
wire ts_sdram;
reg ts_sdc;
reg ts_omit;
reg omit;
reg [31:0] addr;
reg [31:0] data0;
reg [31:0] data1;
reg [31:0] reqCnt;
reg [31:0] gntCnt;
integer i;
// ******************************** MODULE BODY ********************************
// -----------------------------------------------------------------------------
// Reset
always @(posedge clk or negedge reset_n)
if (!reset_n)
rst <= #1 2'b11;
else
rst <= #1 {rst[0], 1'b0};
always @(posedge clk or negedge reset_n)
if (!reset_n)
reset <= #1 1'b1;
else
reset <= #1 rst[1];
// -----------------------------------------------------------------------------
// Time Count
// タスクのカウンター
always @(posedge clk or negedge reset_n)
if (!reset_n)
tsc <= #1 32'd0;
else if (~&tsc & !ts_hold)
tsc <= #1 tsc + 32'd1;
always @(posedge clk or negedge reset_n)
if (!reset_n)
omit <= #1 1'b1;
else
omit <= #1 ts_omit;
// DDR制御の非IDLE、終了判定に使用
assign ts_sdram = |sdc_0.cntl_0.state;
// -----------------------------------------------------------------------------
// Parameter Access
assign pReq = ts_req;
assign pAddr = ts_addr;
assign ts_gnt = pGnt;
// -----------------------------------------------------------------------------
// Initialize Memory
// DDRモデル内のメモリ値をインクリメンタルデータに初期化、DDRモデルが変われば変数名等変更が必要
always @(ts_sdc)
if (ts_sdc)
for (i=0; i<'h10_0000; i=i+1) begin // 8MB
addr = 8*i;
data0 = 2*i;
data1 = 2*i + 1;
sdram_0.memory[{addr[5:3], addr[27:13], addr[12:6]}]
= {data1, data0};
end
// -----------------------------------------------------------------------------
// Initialize Master
// マスターの内のメモリ値をインクリメンタルデータに初期化
always @(ts_sdc)
if (ts_sdc)
for (i=0; i<'h10_0000; i=i+1) begin // 8MB
addr = i;
data0 = 2*i;
data1 = 2*i + 1;
master_0.mem[addr]
= {data1, data0};
end
// -----------------------------------------------------------------------------
// Master
// 上位アドレスは変化しないようマスク(メモリ消費量や同じアドレスへのR/Wが重なる確率を上げるため)
master #(32'h000ffff8, 1, 2) master_0 (
iReq, iGnt, iRxw, iAddr,
iWrStrb, iWrAck, 1'b0, iWrData, iWrMask,
iRdStrb, iRdAck, 1'b0, iRdData,
omit,
reset, clk
);
// -----------------------------------------------------------------------------
// Body
// RowアドレスはiAddrの13bit目からマッピング
sdc #(13) sdc_0 (
.iReq (iReq),
.iGnt (iGnt),
.iRxw (iRxw),
.iAddr (iAddr),
.iWrAck (iWrAck),
.iWrData (iWrData),
.iWrMask (iWrMask),
.iRdAck (iRdAck),
.iRdData (iRdData),
.pReq (pReq),
.pGnt (pGnt),
.pAddr (pAddr),
.cs_n (sd_cs_n),
.ras_n (sd_ras_n),
.cas_n (sd_cas_n),
.we_n (sd_we_n),
.addr (sd_addr),
.ba (sd_ba),
.wdvld (sd_wdvldt),
.wdvldd (sd_wdvldd),
.wd (sd_wd),
.wdqm (sd_wdqm),
.rdvld (sd_rdvld),
.rd (sd_rd),
.reg_pACCW (reg_pACCW),
.reg_pACCR (reg_pACCR),
.reg_pCOM (reg_pCOM),
.reg_pFAW (reg_pFAW),
.reg_pRRD (reg_pRRD),
.reg_dTWR (reg_dTWR),
.reg_dTRW (reg_dTRW),
.reg_dWL (reg_dWL),
.reg_dRL (reg_dRL),
.clk (clk),
.clk_n (clk_n),
.reset_n (reset_n)
);
// -----------------------------------------------------------------------------
// Statistics
// 使用効率を出すため、リクエスト期間と受付期間を計測
always @(posedge clk)
if (reset) begin
reqCnt <= #1 32'd0;
gntCnt <= #1 32'd0;
end
else if (!omit) begin
reqCnt <= #1 reqCnt + 32'd1;
gntCnt <= #1 gntCnt + (iReq & iGnt);
end
// -----------------------------------------------------------------------------
// Clock
// ここから先はI/O部品
dobuf1 cbuf_0 (
.datain (clk),
.dataout (ddr_clk_p),
.dataout_b (ddr_clk_n)
);
// -----------------------------------------------------------------------------
// Command Buffer
obuf26 abuf_0 (
.datain_h ({sd_cs_n, sd_ras_n, sd_cas_n, sd_we_n,
sd_cke, sd_ba, sd_addr,
sd_odt, sd_reset_n
}),
.datain_l ({sd_cs_n, sd_ras_n, sd_cas_n, sd_we_n,
sd_cke, sd_ba, sd_addr,
sd_odt, sd_reset_n
}),
.dataout ({ddr_cs_n, ddr_ras_n, ddr_cas_n, ddr_we_n,
ddr_cke, ddr_ba, ddr_addr,
ddr_odt, ddr_reset_n
}),
.outclock (ddr_clk_180)
);
// -----------------------------------------------------------------------------
// DQM
obuf1 qbuf_0 (
.datain_h (sd_wdqm[0]),
.datain_l (sd_wdqm[1]),
.dataout (ddr_dqm),
.outclock (ddr_clk_270)
);
// -----------------------------------------------------------------------------
// DQS
diobuf1 sbuf_0 (
.datain (ddr_dqsout),
.dataout (ddr_dqsin),
.dataio (ddr_dqs_p),
.dataio_b (ddr_dqs_n),
.oe (ddr_dqs_poe),
.oe_b (ddr_dqs_noe)
);
// -----------------------------------------------------------------------------
// Data Lane
// AlteraのALTDQ_DQSを模したモデル
dlyd dlyd_0 (
.bidir_dq_input_data_in (ddr_din),
.bidir_dq_oe_in ({8{sd_wdvld}}),
.bidir_dq_output_data_in_high (sd_wd[7:0]),
.bidir_dq_output_data_in_low (sd_wd[15:8]),
.dll_delayctrlin (6'h00),
.dq_output_reg_clk (ddr_clk_270),
.dq_output_reg_clkena (1'b1),
.dqs_enable_in (sd_rdvld),
.dqs_input_data_in (ddr_dqsin),
.dqs_oe_in (sd_wdvld),
.dqs_output_data_in_high (sd_wdvldd),
.dqs_output_data_in_low (1'b0),
.dqs_output_reg_clk (ddr_clk_0),
.dqs_output_reg_clkena (1'b1),
.dqsn_oe_in (sd_wdvld),
.bidir_dq_input_data_out_high (sd_rd[15:8]),
.bidir_dq_input_data_out_low (sd_rd[7:0]),
.bidir_dq_oe_out (ddr_oe),
.bidir_dq_output_data_out (ddr_dout),
.dqs_bus_out (ddr_dqs_pbus),
.dqs_oe_out (ddr_dqs_poe),
.dqs_output_data_out (ddr_dqsout),
.dqsn_oe_out (ddr_dqs_noe)
);
iobuf8 dbuf_0 (
.datain (ddr_dout),
.oe (ddr_oe),
.dataio (ddr_dq),
.dataout (ddr_din)
);
// -----------------------------------------------------------------------------
// SDRAM
// USEMがセットされていれば、付録のddr.vを使う
// DDRモデルはMicronのddr.vを使うことを前提にしている(SpeedバージョンはSG25E)
// Micronのddr.vは同じディレクトリにddr2_parameters.vhが必要
`ifdef USEM
ddr_emu sdram_0 (
ddr_clk_p, ddr_clk_n,
ddr_cke, ddr_cs_n, ddr_ras_n, ddr_cas_n, ddr_we_n, ddr_dqm,
ddr_ba, ddr_addr, ddr_dq, ddr_dqs_p, ddr_dqs_n, ddr_rdqs_n, ddr_odt
);
`else
`define x8
`define sg25E
ddr2 sdram_0 (
ddr_clk_p, ddr_clk_n,
ddr_cke, ddr_cs_n, ddr_ras_n, ddr_cas_n, ddr_we_n, ddr_dqm,
ddr_ba, ddr_addr[14:0], ddr_dq, ddr_dqs_p, ddr_dqs_n, ddr_rdqs_n, ddr_odt
);
`endif
// **************************** FUNCTIONS and TASKS ****************************
// DDRの初期化、マスターアクセスの許可(omit=0)、リフレッシュの挿入、終了処理を行う
always @(
tsc or
ts_gnt or ts_sdram or
omit or
reqCnt or gntCnt
) begin
ts_req = 1'b0;
ts_addr = 32'h00000000;
ts_hold = 1'b0;
ts_sdc = 1'b0;
ts_omit = omit;
case (tsc)
// -----------------------------------------------------------------------------
// Initialize SDRAM
// -----------------------------------------------------------------------------
// DDR2:
// AL=3, CL=5, WR=6, RL=AL+CL=8, RL=AL+CL=8, WL=RL-1=7
// tRP=5(12.5ns), tRRD=3(7.5ns), tRFC=79/28000(197.5ns/70us)
// tRAS=16(40ns), tRC=22(55ns), tWTR=3(7.5ns), tFAW=18(45ns)
//
// FAW = tFAW = 18
// RRD = tRRD = 3
// CP = tRFC = 79
// APR = tRC = 22
// = tRAS+tRP = 21
// = 2+RL+BL/2+tRP = 19
// APW = tRC = 22
// = tRAS+tRP = 21
// = 2+WL+BL/2+tRP+WR = 24
// RCL = RL = 8
// WCL = WL = 7
// TRW = RL-WL+BL/2+1 = 6
// TWR = WL+BL/2-AL+tWTR = 11
//
1: begin
$display("");
$display("********************");
$display("* Initialize Start *");
$display("********************");
end
10: Write (32'h04000200); // (Precharge-all)
11: Write (32'h00001000); // (EMRS1:0)
12: Write (32'h00002000); // (EMRS2:0)
13: Write (32'h00003000); // (EMRS3:0)
14: Write (32'h0b530000); // (MRS:WR=6,DLL=1,CL=5,BL=8)
15: Write (32'h04000200); // (Precharge-all)
16: Write (32'h00000400); // (Refresh)
17: Write (32'h00000400); // (Refresh)
18: Write (32'h0a530000); // (MRS:WR=6,DLL=0,CL=5,BL=8)
19: Write (32'h03981000); // (EMRS1:OCD=def,AL=3)
20: Write (32'h00181000); // (EMRS1:OCD=exit,AL=3)
// -----------------------------------------------------------------------------
// SDRAM Initial Value Set
// -----------------------------------------------------------------------------
30: ts_sdc = 1'b1;
// -----------------------------------------------------------------------------
// Master Access Start
// -----------------------------------------------------------------------------
50: begin
$display("");
$display("****************");
$display("* Access Start *");
$display("****************");
ts_omit = 1'b0;
end
// -----------------------------------------------------------------------------
// Refresh Test
// -----------------------------------------------------------------------------
// リフレッシュを要求(実際はタイマー起動すべき)
293: Write (32'h00000400); // (Refresh)
// -----------------------------------------------------------------------------
// Finalize
// -----------------------------------------------------------------------------
ST: ts_omit = 1'b1;
ST+1: ts_hold = iReq | ts_sdram;
ST+2: begin
$display("");
$display("********************");
$display("* Access Terminate *");
$display("********************");
$display("");
// DDRの使用効率、4を掛けているのはバースト補正
$display("Density: %d/%d\t(%3d%% )", gntCnt<<2, reqCnt, 400*gntCnt/reqCnt);
$display("");
$finish;
end
endcase
end
// -----------------------------------------------------------------------------
// Task
// -----------------------------------------------------------------------------
task Write;
input [31:0] Addr;
begin
ts_req = 1'b1;
ts_addr = Addr;
ts_hold = !ts_gnt;
end
endtask
// *****************************************************************************
endmodule
// *****************************************************************************
/* **************************** MODULE PREAMBLE ********************************
Copyright (c) 2011, ArchiTek
This document constitutes confidential and proprietary information
of ArchiTek. All rights reserved.
*/
// *****************************************************************************
module obuf1 (
datain_h, datain_l, outclock, dataout
);
input datain_h;
input datain_l;
output dataout;
input outclock;
reg dataout_h, dataout_l;
always @(posedge outclock) begin
dataout_h <= #1 datain_h;
dataout_l <= #1 datain_l;
end
assign dataout = outclock ? dataout_h : dataout_l;
endmodule
// *****************************************************************************
module obuf26 (
datain_h, datain_l, outclock, dataout
);
input [25:0] datain_h, datain_l;
output [25:0] dataout;
input outclock;
reg [25:0] dataout_h, dataout_l;
always @(posedge outclock) begin
dataout_h <= #1 datain_h;
dataout_l <= #1 datain_l;
end
assign dataout = outclock ? dataout_h : dataout_l;
endmodule
// *****************************************************************************
module dobuf1 (
datain, dataout, dataout_b
);
input datain;
output dataout;
output dataout_b;
assign dataout = datain;
assign dataout_b = ~datain;
endmodule
// *****************************************************************************
module iobuf8 (
datain, oe, dataio, dataout
);
input [7:0] datain;
output [7:0] dataout;
inout [7:0] dataio;
input [7:0] oe;
assign dataout = dataio;
assign dataio[7] = !oe[7] ? 1'bz : datain[7];
assign dataio[6] = !oe[6] ? 1'bz : datain[6];
assign dataio[5] = !oe[5] ? 1'bz : datain[5];
assign dataio[4] = !oe[4] ? 1'bz : datain[4];
assign dataio[3] = !oe[3] ? 1'bz : datain[3];
assign dataio[2] = !oe[2] ? 1'bz : datain[2];
assign dataio[1] = !oe[1] ? 1'bz : datain[1];
assign dataio[0] = !oe[0] ? 1'bz : datain[0];
endmodule
// *****************************************************************************
module diobuf1 (
datain, dataout, dataio, dataio_b, oe, oe_b
);
input datain;
output dataout;
inout dataio;
inout dataio_b;
input oe;
input oe_b;
assign dataout = dataio;
assign dataio = !oe ? 1'bz : datain;
assign dataio_b = !oe ? 1'bz : ~datain;
endmodule
// *****************************************************************************
/* **************************** MODULE PREAMBLE ********************************
Copyright (c) 2011, ArchiTek
This document constitutes confidential and proprietary information
of ArchiTek. All rights reserved.
*/
// ***************************** MODULE HEADER *********************************
module dlyd (
bidir_dq_input_data_in, bidir_dq_oe_in,
bidir_dq_output_data_in_high, bidir_dq_output_data_in_low,
dll_delayctrlin,
dq_output_reg_clk, dq_output_reg_clkena,
dqs_enable_in, dqs_input_data_in, dqs_oe_in,
dqs_output_data_in_high, dqs_output_data_in_low,
dqs_output_reg_clk, dqs_output_reg_clkena,
dqsn_oe_in,
bidir_dq_input_data_out_high, bidir_dq_input_data_out_low,
bidir_dq_oe_out, bidir_dq_output_data_out,
dqs_bus_out, dqs_oe_out, dqs_output_data_out, dqsn_oe_out
);
// *************************** I/O DECLARATIONS ********************************
input [7:0] bidir_dq_input_data_in;
input [7:0] bidir_dq_oe_in;
input [7:0] bidir_dq_output_data_in_high;
input [7:0] bidir_dq_output_data_in_low;
input [5:0] dll_delayctrlin;
input dq_output_reg_clk;
input dq_output_reg_clkena;
input dqs_enable_in;
input dqs_input_data_in;
input dqs_oe_in;
input dqs_output_data_in_high;
input dqs_output_data_in_low;
input dqs_output_reg_clk;
input dqs_output_reg_clkena;
input dqsn_oe_in;
output [7:0] bidir_dq_input_data_out_high;
output [7:0] bidir_dq_input_data_out_low;
output [7:0] bidir_dq_oe_out;
output [7:0] bidir_dq_output_data_out;
output dqs_bus_out;
output dqs_oe_out;
output dqs_output_data_out;
output dqsn_oe_out;
// ************************** LOCAL DECLARATIONS *******************************
reg [7:0] bidir_dq_input_data_out_high;
reg [7:0] bidir_dq_input_data_out_low;
reg [7:0] dq_data_latch;
reg dqs_bus_out;
reg dqsn_bus_out;
reg dqs;
reg en;
reg [7:0] doea, doeb;
reg [7:0] doa, dob;
reg soea, soeb;
reg soa, sob;
reg dqs_output_data_out;
// ****************************** MODULE BODY **********************************
// -----------------------------------------------------------------------------
// DQ Input
always @(posedge dqs_bus_out)
dq_data_latch <= #1 bidir_dq_input_data_in;
always @(negedge dqs_bus_out) begin
bidir_dq_input_data_out_high
<= #1 bidir_dq_input_data_in;
bidir_dq_input_data_out_low
<= #1 dq_data_latch;
end
always @(negedge dqs or posedge dqs_enable_in)
if (dqs_enable_in)
en <= #1 1'b1;
else
en <= #1 1'b0;
always @(dqs_input_data_in)
dqs <= #2 dqs_input_data_in;
always @(dqs or en) begin
dqs_bus_out = en & dqs;
dqsn_bus_out = ~en | ~dqs;
end
// -----------------------------------------------------------------------------
// DQ OE
always @(posedge dq_output_reg_clk)
if (dq_output_reg_clkena)
doea <= #1 bidir_dq_oe_in;
always @(negedge dq_output_reg_clk)
if (dq_output_reg_clkena)
doeb <= #1 doea;
assign bidir_dq_oe_out = {8{doea & doeb}};
// -----------------------------------------------------------------------------
// DQ Out
always @(posedge dq_output_reg_clk)
if (dq_output_reg_clkena)
doa <= #1 bidir_dq_output_data_in_high;
always @(posedge dq_output_reg_clk)
if (dq_output_reg_clkena)
dob <= #1 bidir_dq_output_data_in_low;
assign bidir_dq_output_data_out = dq_output_reg_clk ? doa : dob;
// -----------------------------------------------------------------------------
// DQS OE
always @(posedge dqs_output_reg_clk)
if (dqs_output_reg_clkena)
soea <= #1 dqs_oe_in;
always @(negedge dqs_output_reg_clk)
if (dqs_output_reg_clkena)
soeb <= #1 soea;
assign dqs_oe_out = soea;
assign dqsn_oe_out = soea;
// -----------------------------------------------------------------------------
// DQS Out
always @(posedge dqs_output_reg_clk)
if (dqs_output_reg_clkena)
soa <= #1 dqs_output_data_in_high;
always @(posedge dqs_output_reg_clk)
if (dqs_output_reg_clkena)
sob <= #1 dqs_output_data_in_low;
always @(dqs_output_reg_clk or soa or sob)
dqs_output_data_out
<= dqs_output_reg_clk ? soa : sob;
// ************************** FUNCTIONS and TASKS ******************************
endmodule
// *****************************************************************************
/* **************************** MODULE PREAMBLE ********************************
Copyright (c) 2011, ArchiTek
This document constitutes confidential and proprietary information
of ArchiTek. All rights reserved.
// x8bit限定
*/
// ***************************** MODULE HEADER *********************************
module ddrse8 (
ck,
ck_n,
cke,
cs_n,
ras_n,
cas_n,
we_n,
dm_rdqs,
ba,
addr,
dq,
dqs,
dqs_n,
rdqs_n,
odt
);
// ************************ PARAMETER DECLARATIONS *****************************
// DDR3なら1で動作、ただしreset_n端子は削ってある
parameter SPD = 0;
// *************************** I/O DECLARATIONS ********************************
input ck;
input ck_n;
input cke;
input cs_n;
input ras_n;
input cas_n;
input we_n;
input dm_rdqs;
input [2:0] ba;
input [15:0] addr;
inout [7:0] dq;
inout dqs;
inout dqs_n;
output rdqs_n;
input odt;
// ************************** LOCAL DECLARATIONS *******************************
// Prepare
reg [63:0] memory[0:33554431]; // 256MB
reg reg_bl; // Burst Length 0:4 1:8
reg reg_bt; // Burst Type 0:Seq 1:Inter
reg [3:0] reg_cl; // Cas Latency
reg [3:0] reg_cwl; // Cas Write Latency
reg [2:0] reg_al; // Additive Latency
wire [3:0] al = reg_cl - reg_al;
// Request
reg [14:0] acta;
reg [9:0] cola;
reg [2:0] actba;
reg rxw;
reg [1:0] vpip[0:31];
reg [1:0] cpip[0:31];
reg [27:0] apip[0:31];
reg [1:0] ca;
wire [3:0] cntl = {cs_n, ras_n, cas_n, we_n};
wire msr = (cntl == 4'b0000);
wire pre = (cntl == 4'b0010);
wire act = (cntl == 4'b0011);
wire com = (cntl[3:1] == 3'b010);
wire put = com | (|ca);
// Write
reg wr;
reg [2:0] waddpt;
reg [2:0] waddnt;
reg [27:0] lwaddr;
wire [4:0] wl = SPD ? (al + reg_cwl - 'h1) : (reg_al + reg_cl - 'h2);
wire [1:0] wp = cpip[wl];
wire [27:0] waddr = apip[wl];
wire [2:0] waddp = {wp, 1'b0} + waddr[2:0];
wire [2:0] waddn = {wp, 1'b1} + waddr[2:0];
wire [63:0] wdata = memory[lwaddr[27:3]];
wire [63:0] wvldp = {{56{1'b0}}, {8{~dm_rdqs}}} << (waddpt * 8);
wire [63:0] wvldn = {{56{1'b0}}, {8{~dm_rdqs}}} << (waddnt * 8);
wire [63:0] wdp = ~wvldp & wdata | wvldp & {8{dq}};
wire [63:0] wdn = ~wvldn & wdata | wvldn & {8{dq}};
// Read
reg rd;
reg [2:0] raddpt;
reg [2:0] raddnt;
reg [63:0] lrdata;
reg [7:0] qp, qn;
reg doe;
reg soe;
wire [4:0] rl = SPD ? (al + reg_cl - 'h1) : (reg_al + reg_cl - 'h1);
wire [1:0] rp = cpip[rl];
wire [27:0] raddr = apip[rl];
wire [2:0] raddp = {rp, 1'b0} + raddr[2:0];
wire [2:0] raddn = {rp, 1'b1} + raddr[2:0];
wire [63:0] rdata = memory[raddr[27:3]];
integer i;
// ****************************** MODULE BODY **********************************
// -----------------------------------------------------------------------------
// Initialize
initial begin
reg_bl = 1'b1;
reg_bt = 1'b0;
reg_cl = 4'h3;
reg_cwl = 4'h3;
ca = 2'h0;
for (i=0; i<32; i=i+1) begin
vpip[i] = 2'h0;
cpip[i] = 2'h0;
apip[i] = 28'h0000000;
end
end
// -----------------------------------------------------------------------------
// Request
always @(posedge ck) // REG
if (msr & (ba[1:0] == 2'b00)) begin
reg_bl <= #1 SPD ? (addr[1:0] == 2'b00) : (addr[2:0] != 3'b010);
reg_bt <= #1 addr[3];
reg_cl <= #1 addr[6:4] + (SPD ? 'h4 : 'h0);
end
always @(posedge ck) // REG
if (msr & (ba[1:0] == 2'b01))
reg_al <= #1 SPD ? {1'b0, addr[4:3]} : addr[5:3];
always @(posedge ck) // REG
if (msr & (ba[1:0] == 2'b10))
reg_cwl <= #1 addr[5:3] + 'h5;
always @(posedge ck) // ACT
if (act) begin
acta <= #1 addr[14:0];
actba <= #1 ba;
end
always @(posedge ck) // COM
if (com) begin
cola <= #1 addr[9:0];
rxw <= #1 cntl[0];
end
always @(posedge ck) // COM
if (pre)
ca <= #1 2'h0;
else if (put)
ca <= #1 (ca + 1'h1) & {reg_bl, 1'b1};
always @(posedge ck) // COM & charge
if (pre)
for (i=0; i<32; i=i+1) begin
vpip[i] <= #1 2'h0;
cpip[i] <= #1 2'h0;
apip[i] <= #1 28'h0000000;
end
else begin
for (i=31; i>0; i=i-1) begin
vpip[i] <= #1 vpip[i-1];
cpip[i] <= #1 cpip[i-1];
apip[i] <= #1 apip[i-1];
end
if (com) begin
vpip[0] <= #1 {put, cntl[0]};
cpip[0] <= #1 ca;
apip[0] <= #1 {actba, acta, addr[9:0]};
end
else begin
vpip[0] <= #1 {put, rxw};
cpip[0] <= #1 ca;
end
end
// -----------------------------------------------------------------------------
// Write
always @(negedge ck) begin
wr <= #1 (vpip[wl] == 2'b10);
waddpt <= #1 reg_bt ? ({wp, 1'b0} ^ waddr[2:0]) : {wp[1] ^ waddr[2], waddp[1:0]};
waddnt <= #1 reg_bt ? ({wp, 1'b1} ^ waddr[2:0]) : {wp[1] ^ waddr[2], waddn[1:0]};
lwaddr <= #1 waddr;
end
always @(posedge ck)
if (wr)
memory[lwaddr[27:3]]
<= #1 wdp;
always @(negedge ck)
if (wr)
memory[lwaddr[27:3]]
<= #1 wdn;
// -----------------------------------------------------------------------------
// Read
always @(negedge ck) begin
rd <= #1 (vpip[rl] == 2'b11);
raddpt <= #1 reg_bt ? ({rp, 1'b0} ^ raddr[2:0]) : {rp[1] ^ raddr[2], raddp[1:0]};
raddnt <= #1 reg_bt ? ({rp, 1'b1} ^ raddr[2:0]) : {rp[1] ^ raddr[2], raddn[1:0]};
lrdata <= #1 rdata;
end
always @(posedge ck)
if (rd) case (raddpt)
3'h0: qp <= #1 lrdata[7:0];
3'h1: qp <= #1 lrdata[15:8];
3'h2: qp <= #1 lrdata[23:16];
3'h3: qp <= #1 lrdata[31:24];
3'h4: qp <= #1 lrdata[39:32];
3'h5: qp <= #1 lrdata[47:40];
3'h6: qp <= #1 lrdata[55:48];
3'h7: qp <= #1 lrdata[63:56];
endcase
always @(negedge ck)
if (rd) case (raddnt)
3'h0: qn <= #1 lrdata[7:0];
3'h1: qn <= #1 lrdata[15:8];
3'h2: qn <= #1 lrdata[23:16];
3'h3: qn <= #1 lrdata[31:24];
3'h4: qn <= #1 lrdata[39:32];
3'h5: qn <= #1 lrdata[47:40];
3'h6: qn <= #1 lrdata[55:48];
3'h7: qn <= #1 lrdata[63:56];
endcase
always @(posedge ck)
doe <= #1 (vpip[rl] == 2'b11);
always @(posedge ck)
soe <= #1 (vpip[rl-1] == 2'b11) | (vpip[rl] == 2'b11);
assign dq = doe ? (ck ? qp : qn) : 8'hzz; // 8'hzz if bi-directional buffer
assign dqs = soe ? ~rdqs_n : 1'bz; // 2'bzz if bi-directional buffer
assign dqs_n = soe ? rdqs_n : 1'bz; // 2'bzz if bi-directional buffer
assign rdqs_n = ck_n | ~doe | ~rd;
// ************************** FUNCTIONS and TASKS ******************************
endmodule
// *****************************************************************************
回路デザイン > 設計例 [DDR制御(論理)] > テスト このページのTOP ▲