URL
https://opencores.org/ocsvn/eco32/eco32/trunk
Subversion Repositories eco32
Compare Revisions
- This comparison shows the changes necessary to convert path
/eco32/trunk/fpga/experiments/memctrl/sim/memctrl-2
- from Rev 312 to Rev 314
- ↔ Reverse comparison
Rev 312 → Rev 314
/ramtest/ramtest.v
0,0 → 1,262
// |
// ramtest.v -- RAM test generator |
// |
|
|
`timescale 1ns/10ps |
`default_nettype none |
|
|
`define SIMULATE |
`define VERBOSE |
|
`define INST_PERIOD 31 |
`define INST_PHASE 19 |
`define DATA_PERIOD 17 |
`define DATA_PHASE 7 |
|
|
// |
// memory test generator |
// |
// Algorithm: Three independent address/data generators |
// produce exactly the same sequence of address/data pairs, |
// although at different times: data write, data read, and |
// instruction read. Three out of four data cycles are writes, |
// one is a read. Instruction reads are also less frequent |
// than data writes: 1/31 < 1/17 * 3/4. The writing process |
// is therefore always ahead of the reading processes, with |
// an increasing gap in between. |
// |
|
module ramtest(clk, rst, |
inst_stb, inst_addr, |
inst_din, inst_ack, |
data_stb, data_we, data_addr, |
data_dout, data_din, data_ack, |
test_ended, test_error); |
input clk; |
input rst; |
output reg inst_stb; |
output [25:0] inst_addr; |
input [63:0] inst_din; |
input inst_ack; |
output reg data_stb; |
output reg data_we; |
output [25:0] data_addr; |
output [63:0] data_dout; |
input [63:0] data_din; |
input data_ack; |
output test_ended; |
output test_error; |
|
reg [4:0] inst_timer; |
reg [4:0] data_timer; |
reg [9:0] data_counter; |
|
wire ir_next; |
wire [21:0] ir_a; |
wire [63:0] ir_d; |
|
wire dw_next; |
wire [21:0] dw_a; |
wire [63:0] dw_d; |
|
wire dr_next; |
wire [21:0] dr_a; |
wire [63:0] dr_d; |
|
`ifdef SIMULATE |
reg error_1; |
reg error_3; |
`endif |
reg error_2; |
reg error_4; |
|
always @(posedge clk) begin |
if (rst) begin |
inst_timer <= 0; |
inst_stb <= 0; |
`ifdef SIMULATE |
error_1 <= 0; |
`endif |
error_2 <= 0; |
end else begin |
if (~test_ended) begin |
if (~inst_stb) begin |
if (inst_timer == `INST_PERIOD - 1) begin |
inst_timer <= 0; |
end else begin |
inst_timer <= inst_timer + 1; |
end |
if (inst_timer == `INST_PHASE) begin |
inst_stb <= 1; |
end |
end else begin |
if (inst_ack) begin |
inst_stb <= 0; |
`ifdef SIMULATE |
`ifdef VERBOSE |
$display("%t: inst read @ 0x%h", $realtime, ir_a); |
$display(" value = 0x%h", inst_din); |
`endif |
if (^inst_din[63:0] === 1'bx) begin |
$display("Warning: Input data has don't cares at %t", |
$realtime); |
error_1 <= 1; |
end |
`endif |
if (inst_din[63:0] != ir_d[63:0]) begin |
error_2 <= 1; |
end |
end |
end |
end |
end |
end |
|
adgen adgen_ir( |
.clk(clk), |
.rst(rst), |
.next(ir_next), |
.addr(ir_a), |
.data(ir_d) |
); |
|
assign ir_next = inst_ack; |
assign inst_addr[25:0] = { 4'h0, ir_a[21:0] }; |
|
always @(posedge clk) begin |
if (rst) begin |
data_timer <= 0; |
data_stb <= 0; |
data_we <= 0; |
data_counter <= 0; |
`ifdef SIMULATE |
error_3 <= 0; |
`endif |
error_4 <= 0; |
end else begin |
if (~test_ended) begin |
if (~data_stb) begin |
if (data_timer == `DATA_PERIOD - 1) begin |
data_timer <= 0; |
end else begin |
data_timer <= data_timer + 1; |
end |
if (data_timer == `DATA_PHASE) begin |
data_stb <= 1; |
data_we <= ~&data_counter[1:0]; |
end |
end else begin |
if (data_ack) begin |
data_stb <= 0; |
data_we <= 0; |
data_counter <= data_counter + 1; |
`ifdef SIMULATE |
`ifdef VERBOSE |
if (data_we == 1) begin |
$display("%t: data write @ 0x%h", $realtime, dw_a); |
$display(" value = 0x%h", dw_d); |
end else begin |
$display("%t: data read @ 0x%h", $realtime, dr_a); |
$display(" value = 0x%h", data_din); |
end |
`endif |
if (data_we == 0 && |
^data_din[63:0] === 1'bx) begin |
$display("Warning: Input data has don't cares at %t", |
$realtime); |
error_3 <= 1; |
end |
`endif |
if (data_we == 0 && |
data_din[63:0] != dr_d[63:0]) begin |
error_4 <= 1; |
end |
end |
end |
end |
end |
end |
|
adgen adgen_dw( |
.clk(clk), |
.rst(rst), |
.next(dw_next), |
.addr(dw_a), |
.data(dw_d) |
); |
|
adgen adgen_dr( |
.clk(clk), |
.rst(rst), |
.next(dr_next), |
.addr(dr_a), |
.data(dr_d) |
); |
|
assign dw_next = data_ack & data_we; |
assign dr_next = data_ack & ~data_we; |
assign data_addr[25:0] = { 4'h0, data_we ? dw_a[21:0] : dr_a[21:0] }; |
assign data_dout[63:0] = dw_d[63:0]; |
|
assign test_ended = &data_counter[9:0]; |
|
`ifdef SIMULATE |
assign test_error = error_1 | error_2 | error_3 | error_4; |
`else |
assign test_error = error_2 | error_4; |
`endif |
|
endmodule |
|
|
// |
// address & data generator |
// |
// compute pseudo-random 32-bit address |
// and 64-bit data on request |
// |
|
module adgen(clk, rst, |
next, addr, data); |
input clk; |
input rst; |
input next; |
output [21:0] addr; |
output [63:0] data; |
|
reg [31:0] a; |
reg [63:0] d; |
|
always @(posedge clk) begin |
if (rst) begin |
a[31: 0] <= 32'hC70337DB; |
d[63:32] <= 32'h7F4D514F; |
d[31: 0] <= 32'h75377599; |
end else begin |
if (next) begin |
if (a[0] == 0) begin |
a[31:0] <= a[31:0] >> 1; |
end else begin |
a[31:0] <= (a[31:0] >> 1) ^ 32'hD0000001; |
end |
if (d[32] == 0) begin |
d[63:32] <= d[63:32] >> 1; |
end else begin |
d[63:32] <= (d[63:32] >> 1) ^ 32'hD0000001; |
end |
if (d[0] == 0) begin |
d[31:0] <= d[31:0] >> 1; |
end else begin |
d[31:0] <= (d[31:0] >> 1) ^ 32'hD0000001; |
end |
end |
end |
end |
|
assign addr[21:0] = a[21:0]; |
assign data[63:0] = d[63:0]; |
|
endmodule |
/memtest.v
0,0 → 1,108
// |
// memtest.v -- test bench for memory controller |
// |
|
|
`include "ramtest/ramtest.v" |
`include "ramctrl/ramctrl.v" |
|
|
`timescale 1ns/10ps |
`default_nettype none |
|
|
module memtest; |
|
reg clk2; // system clock, 100 MHz |
reg clk; // system clock, 50 MHz |
reg clk_ok_in; // clocks are stable, input |
reg clk_ok; // system clocks are stable |
reg rst_in; // reset, input |
reg rst; // system reset |
|
wire inst_stb; |
wire [25:0] inst_addr; |
wire [63:0] inst_to_cache; |
wire inst_ack; |
wire inst_timeout; |
|
wire data_stb; |
wire data_we; |
wire [25:0] data_addr; |
wire [63:0] data_to_mctrl; |
wire [63:0] data_to_cache; |
wire data_ack; |
wire data_timeout; |
|
wire test_ended; |
wire test_error; |
|
// simulation control |
initial begin |
#0 $timeformat(-9, 1, " ns", 12); |
$dumpfile("dump.vcd"); |
$dumpvars(0, memtest); |
clk2 = 1; |
clk = 0; |
clk_ok_in = 0; |
rst_in = 1; |
#43 clk_ok_in = 1; |
#200360 rst_in = 0; |
#488900 $finish; |
end |
|
// clock generator, 100 MHz |
always begin |
#5 clk2 = ~clk2; // 10 nsec cycle time |
end |
|
// clock generator, 50 MHz |
always begin |
#10 clk = ~clk; // 20 nsec cycle time |
end |
|
// clk_ok synchronizer |
always @(posedge clk) begin |
clk_ok <= clk_ok_in; |
end |
|
// reset synchronizer |
always @(posedge clk) begin |
rst <= rst_in; |
end |
|
ramctrl ramctrl_1( |
.clk_ok(clk_ok), |
.clk(clk2), |
.inst_stb(inst_stb), |
.inst_addr(inst_addr[25:0]), |
.inst_dout(inst_to_cache[63:0]), |
.inst_ack(inst_ack), |
.inst_timeout(inst_timeout), |
.data_stb(data_stb), |
.data_we(data_we), |
.data_addr(data_addr[25:0]), |
.data_din(data_to_mctrl[63:0]), |
.data_dout(data_to_cache[63:0]), |
.data_ack(data_ack), |
.data_timeout(data_timeout) |
); |
|
ramtest ramtest_1( |
.clk(clk), |
.rst(rst), |
.inst_stb(inst_stb), |
.inst_addr(inst_addr[25:0]), |
.inst_din(inst_to_cache[63:0]), |
.inst_ack(inst_ack | inst_timeout), |
.data_stb(data_stb), |
.data_we(data_we), |
.data_addr(data_addr[25:0]), |
.data_dout(data_to_mctrl[63:0]), |
.data_din(data_to_cache[63:0]), |
.data_ack(data_ack | data_timeout), |
.test_ended(test_ended), |
.test_error(test_error) |
); |
|
endmodule |
/ramctrl/k4s561632e.v
0,0 → 1,3349
/*============================================================================= |
* Copyright(c) Samsung Electronics Co., 1997,1998. All rights reseved. |
* |
* Verilog Behavioral Model of Synchronous 256 SDRAM |
* |
* Description : This is a synchrounous high data rate DRAM, |
* fabricated with SAMSUNG's high performance |
* CMOS technology. |
* |
* Revision No. : V4.5 |
* date : Jan. 21. 2002 |
* |
*===============================================================================*/ |
|
`define M256 |
`define LVTTL |
`define NBANK4 |
`define X16 |
`define S75 |
`define v |
|
`ifdef LVTTL //M256+G6 |
`ifdef X16 |
`ifdef S75 |
`define tCCmin 7.5 // clock minimum cycle time |
`define tCCmax 1000 // clock maximun cycle time |
`define tCC3 7.5 // clock minimun cycle time at cas latency=3 |
`define tCC2 10 // clock minimun cycle time at cas latency=2 |
`define tCH 2.5 // clock high pulse width |
`define tCL 2.5 // clock low pulse width |
`define tSS 1.5 // input setup time |
`define tSH 0.8 // input hold time |
`define tRRD 15 // row to row delay(min) |
`define tRCD 20 // ras to cas delay(min) |
`define tRP 20 // row precharge time(min) |
`define tRASmin 45 // row active minimum time |
`define tRASmax 100000 // row active maximum time |
`define tRC 65 // row cycle time(min) |
`define tCCD 7.5 // col. address to col. address delay: |
`define tSAC2 6 |
`define tSAC3 5.4 |
`define tSHZ2 6 |
`define tSHZ3 5.4 |
`endif //end of S75 |
`ifdef S60 |
`define tCCmin 6 // clock minimum cycle time |
`define tCCmax 1000 // clock maximun cycle time |
`define tCC3 6 // clock minimun cycle time at cas latency=3 |
`define tCH 2.5 // clock high pulse width |
`define tCL 2.5 // clock low pulse width |
`define tSS 1.5 // input setup time |
`define tSH 1 // input hold time |
`define tRRD 12 // row to row delay(min) |
`define tRCD 18 // ras to cas delay(min) |
`define tRP 18 // row precharge time(min) |
`define tRASmin 42 // row active minimum time |
`define tRASmax 100000 // row active maximum time |
`define tRC 60 // row cycle time(min) |
`define tCCD 6 // col. address to col. address delay: |
`define tSAC3 5 |
`define tSHZ3 5 |
`endif //end of S60 |
`endif //end of X16 |
`ifdef X8 |
`ifdef S75 |
`define tCCmin 7.5 // clock minimum cycle time |
`define tCCmax 1000 // clock maximun cycle time |
`define tCC3 7.5 // clock minimun cycle time at cas latency=3 |
`define tCC2 10 // clock minimun cycle time at cas latency=2 |
`define tCH 2.5 // clock high pulse width |
`define tCL 2.5 // clock low pulse width |
`define tSS 1.5 // input setup time |
`define tSH 0.8 // input hold time |
`define tRRD 15 // row to row delay(min) |
`define tRCD 20 // ras to cas delay(min) |
`define tRP 20 // row precharge time(min) |
`define tRASmin 45 // row active minimum time |
`define tRASmax 100000 // row active maximum time |
`define tRC 65 // row cycle time(min) |
`define tCCD 7.5 // col. address to col. address delay: |
`define tSAC2 6 |
`define tSAC3 5.4 |
`define tSHZ2 6 |
`define tSHZ3 5.4 |
`endif //end of S75 |
`endif //end of X8 |
`ifdef X4 |
`ifdef S75 |
`define tCCmin 7.5 // clock minimum cycle time |
`define tCCmax 1000 // clock maximun cycle time |
`define tCC3 7.5 // clock minimun cycle time at cas latency=3 |
`define tCC2 10 // clock minimun cycle time at cas latency=2 |
`define tCH 2.5 // clock high pulse width |
`define tCL 2.5 // clock low pulse width |
`define tSS 1.5 // input setup time |
`define tSH 0.8 // input hold time |
`define tRRD 15 // row to row delay(min) |
`define tRCD 20 // ras to cas delay(min) |
`define tRP 20 // row precharge time(min) |
`define tRASmin 45 // row active minimum time |
`define tRASmax 100000 // row active maximum time |
`define tRC 65 // row cycle time(min) |
`define tCCD 7.5 // col. address to col. address delay: |
`define tSAC2 6 |
`define tSAC3 5.4 |
`define tSHZ2 6 |
`define tSHZ3 5.4 |
`endif //end of S75 |
`endif //end of X4 |
`endif //end of LVTTL |
|
|
/*================================================================== |
* Copyright(c) Samsung Electronics Co., 1997,1998. All rights reseved. |
* |
* Verilog Behavioral Model of Synchronous DRAM |
* |
* Device: - 16M SDRAM(2nd Gen., 3rd Gen., 4th Gen., 5th Gen.) |
* - 64M SDRAM(2nd Gen., 3rd Gen., 4th Gen., 5th Gen.) |
* - 128M SDRAM(1st Gen., 2nd Gen.,) |
* - 256M SDRAM(2nd Gen.) |
* |
* Description : This is a synchrounous high data rate DRAM, |
* fabricated with SAMSUNG's high performance |
* CMOS technology. |
* |
* Developer : Jae-Ha Kim. |
* CAE Team. Semiconductor R&D Centor. |
* Semiconductor Division. Samsung Electronics Co. |
* |
* Revision : Yong-Cheol Bae. ( e-mail: jjbae@samsung.co.kr ) |
* 1.0~2.3 DRAM2 Design. Semiconductor R&D Centor. |
* Semiconductor Division. Samsung Electronics Co. |
* Revision : Kyung-Woo Nam. ( e-mail: aboverim@samsung.co.kr ) |
* 3.0~ DRAM2 Design. Semiconductor R&D Centor. |
* Semiconductor Division. Samsung Electronics Co. |
*================================================================== |
* Revision No. : V2.3 |
* date : Aug. 20. 1997 |
* : Oct. 22. 1997 |
* : Jan. 15. 1998 - 16M 4Gen. & 64M 3Gen. spec update |
* : Jun. 30. 1998 - 16M 4Gen. & 64M 3Gen. & 2Mx32 & |
* 128M 1Gen. & 256M 2Gen. AC spec update |
* : Oct. 08. 1998 - all-bank precharge revision |
* bank note change: ba0=MSB,ba1=LSB @ 4banks |
* : Nov. 18. 1998 - option set for verbose (e.g. +define+v ) |
* 128M 2Gen. AC spec added. |
* conformed model through verilog-XL 2.6.27 |
* Revision No. : V3.0 |
* date : Apr. 07. 1999 - tRDL=2 |
* 1. parameterize auto-precharge address : ADDR_AP |
* 2. divide auto-precharge process read/write |
* 3. divide precharge_flag_kill process normal/read_autopre/write_autopre |
* 4. generate wr_autoprecharge2 process excuting when tRDL=2 |
* 5. modify same-bank-autoprecharge-disable function |
* (disable gapless, other bank interrupt case) |
* Revision No. : V3.1 |
* date : May. 19. 1999 |
* 1. Add 16M 5th Gen. LVTTL(-10,-8,-8.7,-7,-6) |
* 2. Modify 2Mx32 5th Gen. tSAC value |
* Revision No. : V3.2 |
* date : Jun. 11. 1999 |
* 1. Modify -A AC parameter(64M 5th, 128M 2th, 256M 2th) |
* Revision No. : V3.3 |
* date : Jun. 24. 1999 |
* 1. After 64MSD3, auto_flagx signal is not used, |
* let auto_flagx be not enabled to device which is after 64MSD3 |
* 2. compile new versions |
* verilog-xl : 2.7.17, NC-verilog : 2.1., VCS : 5.0.1a |
* Revision No. : V3.4 |
* date : Jul. 12. 1999 |
* 1. To prevent roundoff error in AC parameter violation check procedure, |
* define MARGIN paramter. (MARGIN=0.1ns now) |
* Revision No. : V3.5 |
* date : Sep. 28. 1999 |
* 1. Warning message 'tCCmax violation' is appeared during self refresh operation. |
* When self refresh or precharge-power down, clk can be don't care state. (can stay 'low' or 'high'-level) |
* Therefore tCCmax violation should not be checked during self refresh or prech. power down. |
* Revision No. : V3.6 |
* date : Dec. 14. 1999 |
* 1. Make MODELSIM version and add partial REF./VREFi change function for NOKIA |
* Revision No. : V3.7 |
* date : Jul. 11. 2000 |
* 1. Add dynamic memory allocation function using VERILOG-XL PLI, |
* then you must build verilog-XL excutable file containing PLI, and use +define+DYMEM option. |
* Revision No. : V3.8 |
* date : Jul. 13. 2000 |
* 1. Add 128M SDRAM 3rd/4th Gen., 256M SDRAM 3rd Gen. |
* Revision No. : V3.9 |
* date : Feb. 5. 2001 |
* 1. remove CL2 parameter at -A, -7,... when violated, error messages are printed. |
* Revision No. : V4.0 |
* date : Jun. 11. 2001 |
* 1. 128M SDRAM X32 MCP (64M SDRAM X16 7th) parameter added |
* Revision No. : V4.1 |
* date : Jun. 23. 2001 |
* 1. 256M SDRAM 4th parameters are added |
* Revision No. : V4.2 |
* date : Jul. 31. 2001 |
* 1. because array of reg is not work at vcs 6.0, change array of reg to real variable (TRAS_PP, TPRE_P) |
* Revision No. : V4.3 |
* date : Aug. 09. 2001 |
* 1. There is an error that use "<" instead of ">", in tRASmax violation check routine. |
* Revision No. : V4.4 |
* date : Oct. 05. 2001 |
* 1. Add 128M Mobile SDRAM 5th Gen. (8Mx16, D-die) |
* 2. Add 64M Mobile SDRAM 7th Gen. (2Mx32, F-die) |
* Revision No. : V4.5 |
* date : Nov. 23. 2001 |
* 1. Add mobile function (EMRS:PASR/TCSR/DSC, DPD:pin/cmd control) |
* Revision No. : V4.6 |
* date : Jan. 15. 2002 |
* 1. Add 512M SDRAM |
* Revision No. : V4.6 |
* date : Aug. 27. 2002 |
* 1. Add 128M X32 SDRAM |
* Revision No. : V4.7 |
* date : Nov. 25. 2003 |
* 1. Add 256M X32 SDRAM |
* 2. Add 512M X32 SDRAM (DDP) |
* 3. Add 512M X16 SDRAM (DDP: 2CS) |
* 4. Add 1GM X4 SDRAM (DDP: 2CS) |
* 5. Add 1GM X8 SDRAM (DDP: 2CS, 2CKE) |
*================================================================== |
*/ |
|
`timescale 1ns / 10ps |
`default_nettype none |
|
`define K1 1024 |
`define M1 1048576 |
`define BYTE 8 |
|
|
`ifdef CS2 |
`ifdef DPD_PIN |
module sdram_cs2(clk, csb, cke, ba, ad, rasb, casb, web, dqm, dqi, dpdb); |
`else |
module sdram_cs2(clk, csb, cke, ba, ad, rasb, casb, web, dqm, dqi); |
`endif |
`else |
`ifdef DPD_PIN |
module sdram(clk, csb, cke, ba, ad, rasb, casb, web, dqm, dqi, dpdb); |
`else |
module sdram(clk, csb, cke, ba, ad, rasb, casb, web, dqm, dqi); //default port name |
`endif |
`endif |
|
`ifdef M16 |
`define TBITS 16*`M1 |
`define nBank 2 |
`define ADDRTOP 10 |
`define ADDR_AP 10 |
`ifdef G2 |
`define M16G2_M641G |
`else |
`define M16G3_M64G2 |
`define M64G3_M128_M256 |
`endif |
`endif |
|
`ifdef M64 |
`define TBITS 64*`M1 |
`define ADDR_AP 10 |
`ifdef NBANK2 |
`define nBank 2 |
`ifdef X32 |
`define ADDRTOP 11 |
`else |
`define ADDRTOP 12 |
`endif |
`endif |
`ifdef NBANK4 |
`define nBank 4 |
`ifdef X32 |
`define ADDRTOP 10 |
`else |
`define ADDRTOP 11 |
`endif |
`endif |
`define M64_M128_M256 // for prech_reg |
`ifdef G1 |
`define M16G2_M641G |
`else |
`ifdef G2 |
`define M16G3_M64G2 |
`else |
`define M16G4_M64G3 |
`define M64G3_M128_M256 |
`endif |
`endif |
`endif |
|
`ifdef M128 |
`define TBITS 128*`M1 |
`ifdef NBANK4 |
`define nBank 4 |
`define ADDRTOP 11 |
`endif |
`define ADDR_AP 10 |
`define M64_M128_M256 // for prech_reg |
`define M128_M256 // RFU, c_addr 10->11 |
`define M64G3_M128_M256 // from M64G3 |
`define M16G4_M64G3 |
`endif |
`ifdef M256 |
`define TBITS 256*`M1 |
`define nBank 4 |
`ifdef X32 |
`define ADDRTOP 11 |
`else |
`define ADDRTOP 12 |
`endif |
`define ADDR_AP 10 |
`define M64_M128_M256 // for prech_reg |
`define M128_M256 // RFU, c_addr 10->11 |
`define M64G3_M128_M256 // from M64G3 |
`define M16G4_M64G3 |
`endif |
|
`ifdef M512 |
`define TBITS 512*`M1 |
`define nBank 4 |
`define ADDRTOP 12 |
`define ADDR_AP 10 |
`define M64_M128_M256 // for prech_reg |
//`define M128_M256 // RFU, c_addr 10->11 |
`define M64G3_M128_M256 // from M64G3 |
`define M16G4_M64G3 |
`endif |
|
`ifdef M1024 |
`define TBITS 1024*`M1 |
`define nBank 4 |
`define ADDRTOP 12 |
`define ADDR_AP 10 |
`define M64_M128_M256 // for prech_reg |
//`define M128_M256 // RFU, c_addr 10->11 |
`define M64G3_M128_M256 // from M64G3 |
`define M16G4_M64G3 |
`endif |
|
`ifdef M1024 |
`ifdef X4 |
`define M512_M1024_X4 |
`define B 4 |
`define nCOL 12 |
`define PAGEDEPTH 4096 |
`define nDQM 1 |
`endif |
`ifdef X8 |
`define M512_M1024_X8 |
`define B 8 |
`define nCOL 11 |
`define PAGEDEPTH 2048 |
`define nDQM 1 |
`endif |
`else |
|
`ifdef M512 |
`ifdef X4 |
`define M512_M1024_X4 |
`define B 4 |
`define nCOL 12 |
`define PAGEDEPTH 4096 |
`define nDQM 1 |
`endif |
`ifdef X8 |
`define M512_M1024_X8 |
`define B 8 |
`define nCOL 11 |
`define PAGEDEPTH 2048 |
`define nDQM 1 |
`endif |
`ifdef X16 |
`define B 16 |
`ifdef CS2 |
`define nCOL 9 |
`define PAGEDEPTH 512 |
`else |
`define nCOL 10 |
`define PAGEDEPTH 1024 |
`endif |
`define nDQM 2 |
`endif |
`ifdef X32 |
`define B 32 |
`define nCOL 9 |
`define PAGEDEPTH 512 |
`define nDQM 4 |
`endif |
`else |
`ifdef M256 |
`ifdef X4 |
`define M128_M256_X4 // 98.6.30 BYC |
`define B 4 // number of bit(x4) |
`define nCOL 11 |
`define PAGEDEPTH 2048 |
`define nDQM 1 |
`endif |
`ifdef X8 |
`define B 8 // number of bit(x8) |
`define nCOL 10 |
`define PAGEDEPTH 1024 |
`define nDQM 1 |
`endif |
`ifdef X16 |
`define B 16 // number of bit(x16) |
`define nCOL 9 |
`define PAGEDEPTH 512 |
`define nDQM 2 |
`endif |
`ifdef X32 |
`define B 32 // number of bit(x32) |
`define nCOL 9 |
`define PAGEDEPTH 512 |
`define nDQM 4 |
`endif |
`else |
`ifdef M128 |
`ifdef X4 |
`define M128_M256_X4 // 98.6.30 BYC |
`define B 4 // number of bit(x4) |
`define nCOL 11 |
`define PAGEDEPTH 2048 |
`define nDQM 1 |
`endif |
`ifdef X8 |
`define B 8 // number of bit(x8) |
`define nCOL 10 |
`define PAGEDEPTH 1024 |
`define nDQM 1 |
`endif |
`ifdef X16 |
`define B 16 // number of bit(x16) |
`define nCOL 9 |
`define PAGEDEPTH 512 |
`define nDQM 2 |
`endif |
`ifdef X32 |
`define B 32 // number of bit(x32) |
`define nCOL 8 |
`define PAGEDEPTH 256 |
`define nDQM 4 |
`endif |
`else // 64M & 16M |
`ifdef X4 |
`define B 4 // number of bit(x4) |
`define nCOL 10 |
`define PAGEDEPTH 1024 |
`define nDQM 1 |
`endif |
`ifdef X8 |
`define B 8 // number of bit(x8) |
`define nCOL 9 |
`define PAGEDEPTH 512 |
`define nDQM 1 |
`endif |
`ifdef X16 |
`define B 16 // number of bit(x16) |
`define nCOL 8 |
`define PAGEDEPTH 256 |
`define nDQM 2 |
`endif |
`ifdef X32 |
`define B 32 // number of bit(x32) |
`define nCOL 8 |
`define PAGEDEPTH 256 |
`define nDQM 4 |
`endif |
`endif |
`endif |
`endif |
`endif |
|
`ifdef tCC1 |
`else |
`define NO_CL1 |
`endif |
`ifdef tSAC1 |
`else |
`define NO_CL1 |
`endif |
`ifdef tSHZ1 |
`else |
`define NO_CL1 |
`endif |
`ifdef tCC2 |
`else |
`define NO_CL2 |
`endif |
`ifdef tSAC2 |
`else |
`define NO_CL2 |
`endif |
`ifdef tSHZ2 |
`else |
`define NO_CL2 |
`endif |
`ifdef tCC3 |
`else |
`define NO_CL3 |
`endif |
`ifdef tSAC3 |
`else |
`define NO_CL3 |
`endif |
`ifdef tSHZ3 |
`else |
`define NO_CL3 |
`endif |
|
`ifdef tRDL |
`else |
`define tRDL 1 |
`endif |
|
`ifdef DPD_CMD |
`define DPD |
`endif |
`ifdef DPD_PIN |
`define DPD |
`endif |
|
`define HB `B/2 |
`define BIT `B-1:0 |
`define BIT_C `nCOL-1:0 |
`define BIT_T `nCOL+`ADDRTOP:0 |
`define nWORD `TBITS/`B/`nBank |
`define WORD `nWORD-1:0 |
|
inout [`BIT] dqi; |
input [`nBank/2-1:0] ba; |
input [`ADDRTOP:0] ad; |
input rasb,casb,web; |
input clk,cke,csb; |
input [`nDQM-1:0] dqm; |
`ifdef DPD_PIN |
input dpdb; |
`endif |
|
/* |
`ifdef M64 |
`include "m64.ac" |
`endif |
`ifdef M16 |
`include "m16.ac" |
`endif |
`ifdef M128 |
`include "m128.ac" |
`endif |
`ifdef M256 |
`include "m256.ac" |
`endif |
*/ |
|
parameter pwrup_time = 200000, pwrup_check = 1; |
|
wire [`nBank/2 + `ADDRTOP : 0] addr; |
assign addr = {ba, ad}; |
|
wire [`BIT] dqi; |
`ifdef DYMEM |
initial begin |
$damem_declare("mem_a", `B-1, 0, `nWORD-1, 0); |
$damem_declare("mem_b", `B-1, 0, `nWORD-1, 0); |
end |
`else |
reg [`BIT] mem_a[`WORD]; // memory cell array of a bank |
reg [`BIT] mem_b[`WORD]; // memory cell array of b bank |
`endif |
`ifdef NBANK4 |
`ifdef DYMEM |
initial begin |
$damem_declare("mem_c", `B-1, 0, `nWORD-1, 0); |
$damem_declare("mem_d", `B-1, 0, `nWORD-1, 0); |
end |
`else |
reg [`BIT] mem_c[`WORD]; // memory cell array of c bank |
reg [`BIT] mem_d[`WORD]; // memory cell array of d bank |
`endif |
`endif |
|
reg [`BIT] dqo, t_dqo; // output temp. register declaration |
reg [`ADDRTOP:0] r_addr_[`nBank-1:0]; |
reg [`ADDRTOP:0] r_addr; |
reg [`BIT_C] c_addr; // column address |
reg [`BIT_T] m_addr; // merge row and column address |
reg [`BIT] dout_reg[`PAGEDEPTH:0]; |
reg [`BIT] din_rega[`PAGEDEPTH:0]; // din register for a bank |
reg [`BIT] din_regb[`PAGEDEPTH:0]; // din register for b bank |
`ifdef NBANK4 |
reg [`BIT] din_regc[`PAGEDEPTH:0]; // din register for c bank |
reg [`BIT] din_regd[`PAGEDEPTH:0]; // din register for d bank |
`endif |
reg [`BIT] clk_dq; |
reg ptr; |
|
reg [`BIT] ZDATA; |
reg [7:0] ZBYTE; |
|
|
// define mode dependency flag |
`define INITIAL 0 // no bank precharge |
/* |
`define IDLE_AB 1 // both bank precharge |
`define ACT_A 2 // a bank active and b bank precharge |
`define ACT_B 3 // b bank active and a bank precharge |
`define ACT_AB 4 // a & b bank active |
`define IDLE_A 5 // only a bank prechage |
`define IDLE_B 6 // only b bank prechage |
*/ |
|
`define TRUE 1 |
`define FALSE 0 |
`define HIGH 1 |
`define LOW 0 |
`define MARGIN 0.1 |
|
//parameter pwrup_time = 200000, pwrup_check = 1; |
|
/* |
*----------------------------------------------------- |
* We know the phase of external signal |
* by examining the state of its flag. |
*----------------------------------------------------- |
*/ |
|
reg r_bank_addr; // row bank check flag |
reg [`nBank/2-1:0] c_bank_addr; // column bank check flag |
reg [`nBank-1:0] auto_flag; // auto precharge flag |
reg burst_type, // burst type flag |
auto_flagx, |
self_flag; // auto & self refresh flag |
integer kill_bank, wr_kill_bank, rd_kill_bank; |
integer k; |
reg [`nBank-1:0] precharge_flag; // precharge each bank check flag |
reg [`nBank/2:0] prech_reg; // precharge mode (addr[13:12] && addr[10]) |
reg [`nBank/2-1:0] rd_autoprech_reg; |
reg [`nBank/2-1:0] wr_autoprech_reg; |
reg [`nBank/2-1:0] wr_autoprech_reg2; |
reg [`nBank/2-1:0] prev_ba; // bank address of previous command |
reg pwrup_done; |
reg [`nBank-1 : 0] first_pre; |
//reg [8*8 : 1] str; |
integer auto_cnt; |
integer i; |
|
`ifdef M16 |
wire [3:0] RFU = {addr[11:10], addr[8], addr[7]}; |
`endif |
|
`ifdef M64 |
`ifdef NBANK2 |
wire [3:0] RFU = {addr[11:10], addr[8], addr[7]}; |
`endif |
`ifdef NBANK4 |
`ifdef X32 |
wire [4:0] RFU = {addr[12:10], addr[8], addr[7]}; |
`else |
wire [5:0] RFU = {addr[13:10], addr[8], addr[7]}; |
`endif |
`endif |
`endif |
|
`ifdef M128 |
`ifdef NBANK4 |
wire [5:0] RFU = {addr[13:10], addr[8], addr[7]}; |
`endif |
`endif |
|
`ifdef M256 |
`ifdef X32 |
wire [5:0] RFU = {addr[13:10], addr[8], addr[7]}; |
`else |
wire [6:0] RFU = {addr[14:10], addr[8], addr[7]}; |
`endif |
`endif |
|
`ifdef M512 // 98.6.30 BYC |
wire [6:0] RFU = {addr[14:10], addr[8], addr[7]}; |
`endif |
|
`ifdef M1024 |
wire [6:0] RFU = {addr[14:10], addr[8], addr[7]}; |
`endif |
|
reg [`nBank-1:0] Mode; // check mode dependency |
reg [`nBank-1:0] md; |
reg rd_reautoprecharge, wr_reautoprecharge; |
`ifdef NOKIA |
reg REF16M_MODE, REF32M_MODE; |
`endif |
`ifdef DPD |
`define tDPDEXIT 200000 |
reg D_POWERDOWN, D_PDOWN_EXIT; |
integer PROC_DPDEXIT; |
`endif |
`ifdef MOBILE |
reg REF4BANK, REF2BANK, REF1BANK; |
`endif |
integer BL, WBL, CL; // burst length & cas latency |
real tSHZ; // clk to output in hi-Z |
real tSAC; // clk to valid output |
reg write_event;//KyW ... 0408 for VCS |
|
event |
active, // main operation of SDRAM |
modeset, |
read, |
dqo_event, |
write, |
flush_write, |
precharge, |
rd_autoprecharge, |
wr_autoprecharge, |
wr_autoprecharge2, |
precharge_start, |
precharge_flag_kill, |
wr_precharge_flag_kill, |
rd_precharge_flag_kill, |
autorefresh, |
autostart, |
selfrefresh, |
`ifdef DPD |
deeppowerdown, |
d_pdown_exit, |
`endif |
selfexit; |
|
`protect |
|
// initialize each flag |
initial |
begin |
for (i = 0; i < `nBank; i = i + 1) |
auto_flag[i] = `FALSE; |
auto_flagx = `FALSE; |
rd_reautoprecharge =`FALSE; |
wr_reautoprecharge =`FALSE; |
self_flag = `FALSE; |
pwrup_done = `FALSE; |
Mode = `nBank'b0; |
|
for(i = 0; i < `nBank; i = i + 1) |
begin |
first_pre[i] = `TRUE; |
precharge_flag[i] = `FALSE; |
end |
|
ZBYTE = 8'bz; |
for (i = 0; i < `B; i = i + 1) begin |
ZDATA[i] = 1'bz; |
end |
end |
|
//-------------------------------------------------------------- |
//--------- TIMING VIOLATION CHECK ROUTINE |
//-------------------------------------------------------------- |
|
real CUR_TIME, TCKE, TADDR, TRASB, TCASB, TCSB, TWEB, TDQI, TCLK_H, TCLK_L, |
TCC_P, pclk_high, last_read, last_rw; |
|
reg [63:0] TDQM[`nDQM-1:0]; |
|
//real TRAS_P, TCAS_P, TRASA_P, TRASB_P, TPREA_P, TPREB_P, TSELF, TSEXIT; |
// 4 bank |
real TRAS_P, TCAS_P, TSELF, TSEXIT; |
//reg [63:0] TRAS_PP [`nBank-1:0]; |
//reg [63:0] TPRE_P [`nBank-1:0]; |
real TRAS_PP0, TRAS_PP1, TRAS_PP2, TRAS_PP3; |
real TPRE_P0, TPRE_P1, TPRE_P2, TPRE_P3; |
|
reg CKE_FLAG, CSB_FLAG, RASB_FLAG, CASB_FLAG, WEB_FLAG; |
|
//event MRS, ACTIVE; |
reg MRS_SET, WRITE_MODE, READ_MODE, UNMODE, POWERDOWN_MODE, POWERDOWN_MODE1,//KyW ... 0928 for NOKIA claim |
SUSPEND_MODE, AUTOREF_MODE, SELFREF_MODE; |
reg PWR, INIT; |
|
|
`define NOP (RASB_FLAG == `HIGH && CASB_FLAG == `HIGH && WEB_FLAG == `HIGH) |
`define NOP1 (RASB_FLAG == `HIGH && CASB_FLAG == `HIGH) |
/* |
*----------------------------------------------------- |
* wire declaration |
*----------------------------------------------------- |
*/ |
|
reg pcke; |
reg [`nDQM-1:0] dqm_r; |
reg [`nDQM-1:0] dqm_ri; |
|
reg data_read; |
reg tdata_read; |
reg [`BIT] clkh_dq; |
reg [2:0] prev_com; |
reg rw_dqm; |
reg gapless; |
wire pclk = pcke & clk; |
wire [2:0] com = {RASB_FLAG, CASB_FLAG, WEB_FLAG}; |
wire #(TCC_P+0.02) data_read_delay = data_read; // 98.6.29 BYC |
`endprotect |
|
`ifdef X32 |
assign #(tSAC, tSAC, tSHZ) dqi[`B-1:`B-8]= ( data_read & ~dqm_r[3] & ~rw_dqm)?dqo[`B-1:`B-8]:ZBYTE; |
assign #(tSAC, tSAC, tSHZ) dqi[`B-9:`B-16] = ( data_read & ~dqm_r[2] & ~rw_dqm)?dqo[`B-9:`B-16]:ZBYTE; |
assign #(tSAC, tSAC, tSHZ) dqi[`B-17:`B-24]= ( data_read & ~dqm_r[1] & ~rw_dqm)?dqo[`B-17:`B-24]:ZBYTE; |
assign #(tSAC, tSAC, tSHZ) dqi[`B-25:0] = ( data_read & ~dqm_r[0] & ~rw_dqm)?dqo[`B-25:0]:ZBYTE; |
`endif |
`ifdef X16 |
assign #(tSAC, tSAC, tSHZ) dqi[`B-1:`B-8]= ( data_read & ~dqm_r[1] & ~rw_dqm)?dqo[`B-1:`B-8]:ZBYTE; |
assign #(tSAC, tSAC, tSHZ) dqi[`HB-1:0] = ( data_read & ~dqm_r[0] & ~rw_dqm)?dqo[`B-9:0]:ZBYTE; |
`endif |
`ifdef X8 |
assign #(tSAC, tSAC, tSHZ) dqi[`B-1:0] = ( data_read & ~dqm_r & ~rw_dqm)?dqo[`B-1:0]:ZDATA; |
`endif |
`ifdef X4 |
assign #(tSAC, tSAC, tSHZ) dqi[`B-1:0] = ( data_read & ~dqm_r & ~rw_dqm)?dqo[`B-1:0]:ZDATA; |
`endif |
|
`protect |
always @(posedge pclk) begin |
pclk_high <= #0.01 $realtime; |
clkh_dq <= #0.01 dqi; |
end |
|
|
always @(READ_MODE) begin |
// data_read <= repeat(CL-1) @(posedge pclk) READ_MODE; |
// VCS does not support above statement. However Verilog-XL is OK. |
// So, I modified as following statement for VCS. |
#0.1; |
if (READ_MODE == 1'b1) |
data_read <= repeat(CL-1) @(posedge pclk) 1'b1; |
else |
data_read <= repeat(CL-1) @(posedge pclk) 1'b0; |
end |
|
always @(negedge tdata_read) begin |
data_read = tdata_read; |
tdata_read = `TRUE; |
end |
|
always @(dqo_event) |
dqo <= repeat(CL-1) @(posedge pclk) t_dqo; |
|
/* |
*----------------------------------------------------- |
* setup hold check |
*----------------------------------------------------- |
*/ |
|
initial #0.01 pcke = cke; |
|
initial // time variables initialization |
begin |
$timeformat(-9, 1, " ns", 10); |
TCKE = 0; |
TADDR = 0; |
TRASB = 0; |
TCASB = 0; |
TCSB = 0; |
TWEB = 0; |
TDQI = 0; |
TCLK_H = -20; |
TCLK_L = -20; |
TRAS_P = -200; |
TCAS_P = -200; |
TSELF = -200; |
pclk_high = -20; |
last_read = -200; |
last_rw = -20; |
for (i = 0; i < `nDQM; i = i + 1) |
TDQM[i] = 64'b0; |
// 4bank |
//TRAS_PP[0] = -200; |
//TRAS_PP[1] = -200; |
//TPRE_P[0] = -200; |
//TPRE_P[1] = -200; |
TRAS_PP0 = -200; |
TRAS_PP1 = -200; |
TPRE_P0 = -200; |
TPRE_P1 = -200; |
`ifdef NBANK4 |
//TRAS_PP[2] = -200; |
//TRAS_PP[3] = -200; |
//TPRE_P[2] = -200; |
//TPRE_P[3] = -200; |
TRAS_PP2 = -200; |
TRAS_PP3 = -200; |
TPRE_P2 = -200; |
TPRE_P3 = -200; |
`endif |
|
end |
|
initial // mode register variables initialization |
begin |
RASB_FLAG = `HIGH; |
CASB_FLAG = `HIGH; |
CSB_FLAG = `HIGH; |
WEB_FLAG = `HIGH; |
end |
|
initial // mode register variables initialization |
begin |
INIT = `TRUE; |
MRS_SET = `FALSE; |
WRITE_MODE = `FALSE; |
READ_MODE = `FALSE; |
POWERDOWN_MODE = `FALSE; |
POWERDOWN_MODE1 = `FALSE;//KyW ... 0928 for NOKIA claim |
SUSPEND_MODE = `FALSE; |
AUTOREF_MODE = `FALSE; |
SELFREF_MODE = `FALSE; |
`ifdef NOKIA |
REF16M_MODE = `FALSE; |
REF32M_MODE = `FALSE; |
`endif |
`ifdef MOBILE |
REF4BANK = `TRUE; |
REF2BANK = `FALSE; |
REF1BANK = `FALSE; |
`endif |
`ifdef DPD |
D_POWERDOWN = `FALSE; |
D_PDOWN_EXIT = `FALSE; |
PROC_DPDEXIT = 0; |
`endif |
write_event = `FALSE; //KyW ... 0408 for VCS |
end |
|
always @(POWERDOWN_MODE) POWERDOWN_MODE1 = #0.1 POWERDOWN_MODE;//KyW ... 0928 for NOKIA claim |
|
always @( posedge clk ) |
if( PWR == `TRUE ) |
begin : main |
CUR_TIME = $realtime; |
|
if( POWERDOWN_MODE == `TRUE && CKE_FLAG == `TRUE ) |
begin |
if( SELFREF_MODE == `TRUE ) |
begin |
if( CUR_TIME - TSELF < `tRASmin-`MARGIN ) |
begin |
$display("Warning: tRAS violation in self refresh at %t", CUR_TIME); |
end |
->selfexit; |
`ifdef v $display(">> self refresh exit at %t", CUR_TIME); |
`endif |
`ifdef v // $display(">> power down exit at %t", CUR_TIME); |
`endif |
POWERDOWN_MODE = `FALSE; |
CKE_FLAG = `FALSE; |
`endprotect |
`ifdef M16G2_M641G |
pcke <= repeat (1) @(negedge pclk) cke; |
`else |
#0 pcke = cke; |
`endif |
|
end |
`ifdef DPD |
else if (D_POWERDOWN == `TRUE) |
begin |
->d_pdown_exit; |
`ifdef v $display(">> deep power down exit at %t", CUR_TIME); |
`endif |
POWERDOWN_MODE = `FALSE; |
CKE_FLAG = `FALSE; |
end |
`endif |
else |
begin |
`ifdef M16G2_M641G |
if (CUR_TIME - TCKE >= `tPDE-`MARGIN) |
`else |
if( CUR_TIME - TCKE >= `tSS-`MARGIN ) |
`endif |
begin |
`ifdef v $display(">> power down exit at %t", CUR_TIME); |
`endif |
POWERDOWN_MODE = `FALSE; |
CKE_FLAG = `FALSE; |
pcke <= repeat (1) @(negedge pclk) cke; |
end |
else |
begin |
`ifdef M16G2_M641G |
$display("Warning: tPDE violation at %t", CUR_TIME); |
`else |
$display("Warning: tSS Precharge Power Down Exit Setup Violation at %t",CUR_TIME); |
`endif |
disable main; |
end |
end |
end |
|
if( POWERDOWN_MODE == `FALSE) |
begin |
if( CUR_TIME - TCKE < `tSS-`MARGIN ) // check cke setup timing |
$display("Warning: CKE setup violation at %t", CUR_TIME); |
else if( cke && SUSPEND_MODE == `TRUE ) |
begin |
`ifdef v $display(">> clock suspension exit at %t", CUR_TIME); |
`endif |
SUSPEND_MODE = `FALSE; |
pcke <= @(negedge clk) cke; |
end |
else |
pcke <= @(negedge clk) cke; |
end |
|
// clock timing check |
|
TCC_P = CUR_TIME - TCLK_H; // saving current clock period |
|
if( CUR_TIME - TCLK_H < `tCCmin-`MARGIN && POWERDOWN_MODE1 == `FALSE)//KyW ... 0928 for NOKIA claim |
$display("Warning: tCCmin violation at %t", CUR_TIME); |
|
if( CUR_TIME - TCLK_H > `tCCmax+`MARGIN && POWERDOWN_MODE1 == `FALSE)//KyW ... 0928 for NOKIA claim |
$display("Warning: tCCmax violation at %t", CUR_TIME); |
`protect |
if( CUR_TIME - TCLK_L < `tCL-`MARGIN ) |
$display("Warning: tCL violation at %t", CUR_TIME); |
|
// pcke is high |
if( pcke ) begin |
|
// csb timing check |
if( CUR_TIME - TCSB < `tSS-`MARGIN ) |
$display("Warning: CSB setup violation at %t", CUR_TIME); |
else // if( CUR_TIME - TCSB < `tCCmin + `tSS-`MARGIN ) |
CSB_FLAG = csb; |
|
// if chip selected |
if( CSB_FLAG == `LOW ) |
begin |
if( CUR_TIME - TRASB < `tSS-`MARGIN ) |
$display("Warning: RASB setup violation at %t", CUR_TIME); |
else |
RASB_FLAG = rasb; |
|
if( CUR_TIME - TCASB < `tSS-`MARGIN ) |
$display("Warning: CASB setup violation at %t", CUR_TIME); |
else |
CASB_FLAG = casb; |
|
if( CUR_TIME - TWEB < `tSS-`MARGIN ) |
$display("Warning: WEB setup violation at %t", CUR_TIME); |
else |
WEB_FLAG = web; |
|
end |
for (i = 0; i < `nDQM; i = i + 1) begin |
if( CUR_TIME - $bitstoreal(TDQM[i]) < `tSS-`MARGIN ) |
$display("Warning: DQM(%d) setup violation at %t", i, CUR_TIME); |
else begin |
// dqm_r[i] <= @(posedge pclk) dqm[i]; |
// VCS does not support above statement. However Verilog-XL is OK. |
// So, I modified as following statement for VCS. |
dqm_r[i] <= dqm_ri[i]; |
dqm_ri[i] <= dqm[i]; |
end |
end |
end |
|
TCLK_H = CUR_TIME; // the time clock is high |
|
end |
|
/*------------------------------------------ |
* command recognition |
*------------------------------------------ |
*/ |
|
always @( posedge pclk ) |
if( PWR == `TRUE ) |
begin : command |
integer bank_id; |
reg [8*8:1] str; |
|
if( CSB_FLAG == `LOW ) |
begin : command_sel |
if( auto_cnt == -1 ) |
begin |
if( ~ `NOP ) // NOP1 -> NOP because of burst stop |
$display("Warning: NOP required during power-up pause time."); |
disable command_sel; |
end |
|
if( CUR_TIME - TADDR < `tSS-`MARGIN ) |
$display("Warning: Address setup violation at %t", CUR_TIME); |
|
if( `NOP ) // deleted by burst stop -> NOP1 -> NOP |
disable command_sel; |
|
if( AUTOREF_MODE == `TRUE || SELFREF_MODE == `TRUE ) |
begin |
$display("Warning: Illegal command in refresh operation at %t", CUR_TIME); |
disable command_sel; |
end |
`ifdef DPD |
if (D_POWERDOWN == `TRUE) begin |
$display("Warning: Illegal command in deep power down exit at %t", CUR_TIME); |
disable command_sel; |
end |
if (D_PDOWN_EXIT) begin |
if (PROC_DPDEXIT == 0) begin |
if ({RASB_FLAG,CASB_FLAG,WEB_FLAG} == 3'b010) begin |
`ifdef M64_M128_M256 |
`ifdef NBANK2 |
prech_reg[1] = ba; |
prech_reg[0] = addr[`ADDR_AP]; |
`endif |
`ifdef NBANK4 |
prech_reg[2] = ba[1]; |
prech_reg[1] = ba[0]; |
prech_reg[0] = addr[`ADDR_AP]; |
`endif |
`endif |
PROC_DPDEXIT = 1; |
->precharge; |
end |
else $display("Warning: all bank precharge required to complete deep power down mode exit."); |
end |
else if (PROC_DPDEXIT == 1 || PROC_DPDEXIT == 2) begin |
if ({cke,RASB_FLAG,CASB_FLAG,WEB_FLAG} == 4'b1001) begin |
PROC_DPDEXIT = PROC_DPDEXIT + 1; |
->autorefresh; |
end |
else $display("Warning: 2 or more auto refresh required to complete deep power down mode exit."); |
end |
else if (PROC_DPDEXIT == 3) begin |
if ({RASB_FLAG,CASB_FLAG,WEB_FLAG} == 3'b000) begin |
D_PDOWN_EXIT = `FALSE; |
PROC_DPDEXIT = 0; |
->modeset; |
end |
else if ({cke,RASB_FLAG,CASB_FLAG,WEB_FLAG} == 4'b1001) begin |
->autorefresh; |
end |
else $display("Warning: Mode register set required to complete deep power down mode exit."); |
end |
end |
|
`endif |
if( ~pwrup_done ) |
if( auto_cnt < 2 ) |
begin |
case ( {RASB_FLAG,CASB_FLAG,WEB_FLAG} ) |
'b010 : |
begin |
`ifdef M64_M128_M256 |
`ifdef NBANK2 |
prech_reg[1] = ba; |
prech_reg[0] = addr[`ADDR_AP]; |
`endif |
`ifdef NBANK4 |
prech_reg[2] = ba[1]; |
prech_reg[1] = ba[0]; |
prech_reg[0] = addr[`ADDR_AP]; |
`endif |
`endif |
`ifdef M16 |
prech_reg = addr[11:10]; |
`endif |
->precharge; |
end |
'b001 : |
if( cke ) |
begin |
auto_cnt = auto_cnt + 1; |
->autorefresh; |
end |
'b000 : |
begin |
if( MRS_SET == `TRUE ) |
->modeset; |
else if( INIT == `TRUE ) |
begin |
->modeset; |
INIT = `FALSE; |
end |
else |
$display("Warning: MODE register set need 2 clock cycles at %t", CUR_TIME); |
end |
|
default: begin |
$display("Warning: 2 or more auto-refresh required during power up sequence."); |
end |
endcase |
disable command_sel; |
end |
else |
pwrup_done = `TRUE; |
|
case( {RASB_FLAG,CASB_FLAG,WEB_FLAG} ) |
'b000 : |
begin |
if( MRS_SET == `TRUE ) |
->modeset; |
else if( INIT == `TRUE ) |
begin |
->modeset; |
INIT = `FALSE; |
end |
else |
$display("Warning: MODE register set need 2 clock cycles at %t", CUR_TIME); |
end |
'b011 : // active |
begin |
if( MRS_SET == `TRUE ) |
begin |
bank_id = BankSelect(ba); |
str = PrintBank(ba); |
if(Mode[bank_id] == `TRUE) |
$display("Warning: Illegal active (%0s is not precharged) at %t",str,CUR_TIME); |
|
else |
->active; |
end |
|
else if( INIT == `FALSE ) |
$display("Warning: MODE register set need 2 clock cycles at %t",CUR_TIME); |
else if( INIT == `TRUE ) |
$display("Warning: Initial MODE register set must be required before active at %t",CUR_TIME); |
end |
`endprotect |
'b101 : |
begin // read command |
bank_id = BankSelect(ba); |
str = PrintBank(ba); |
gapless = (pclk_high == last_rw && auto_flag[bank_id]) ? |
`TRUE : `FALSE; |
`ifdef M16G4_M64G3 |
if (precharge_flag[bank_id]) |
begin |
$display("Warning: Illegal command in precharge operation at %t",CUR_TIME); |
disable command_sel; |
end |
`else |
if( auto_flagx ) |
begin |
$display("Warning: Illegal command in auto-precharge command at %t",CUR_TIME); |
disable command_sel; |
end |
`endif |
else if( Mode[bank_id] == `TRUE) |
begin |
if( READ_MODE == `TRUE) |
begin |
`ifdef M64G3_M128_M256 |
if (auto_flag[prev_ba] == `TRUE && prev_ba != bank_id) begin |
rd_autoprech_reg = prev_ba; |
->rd_autoprecharge; |
end |
`endif |
READ_MODE = `FALSE; |
#0 disable read_block; |
end |
if( WRITE_MODE == `TRUE) |
begin |
`ifdef M64G3_M128_M256 |
if (auto_flag[prev_ba] == `TRUE && prev_ba != bank_id) begin |
//`ifdef RDL2 |
if (`tRDL == 2) begin |
wr_autoprech_reg2 = prev_ba; |
->wr_autoprecharge2; |
end |
//`else |
else begin |
wr_autoprech_reg = prev_ba; |
->wr_autoprecharge; |
end |
//`endif |
end |
`endif |
WRITE_MODE = `FALSE; |
disable write_block; |
end |
last_read = CUR_TIME; |
prev_com = {RASB_FLAG,CASB_FLAG,WEB_FLAG}; |
prev_ba = ba; |
rw_dqm <= `FALSE; |
#0 ->read; |
end |
|
else |
$display("Warning: Illegal read (%0s is not active) at %t",str,CUR_TIME); |
end |
'b100 : |
begin // write command |
bank_id = BankSelect(ba); |
str = PrintBank(ba); |
if (prev_com == 3'b101) begin |
if (clkh_dq !== `B'bz && data_read_delay == 1'b1) // 98.6.29 BYC |
$display("Warning: HIZ should be issued 1 cycle before write op at %t", CUR_TIME); |
end |
`ifdef M16G2_M641G |
`else |
gapless = (pclk_high == last_rw && auto_flag[bank_id]) |
? `TRUE : `FALSE; |
`endif |
`ifdef M16G4_M64G3 |
if (precharge_flag[bank_id]) |
begin |
$display("Warning: Illegal command in precharge operation at %t",CUR_TIME); |
disable command_sel; |
end |
`else |
if( auto_flagx ) |
begin |
$display("Warning: Illegal command in auto-precharge command at %t",CUR_TIME); |
disable command_sel; |
end |
`endif |
`protect |
else if( Mode[bank_id] == `TRUE) |
begin |
if( READ_MODE == `TRUE ) |
begin |
`ifdef M64G3_M128_M256 |
if (auto_flag[prev_ba] == `TRUE && prev_ba != bank_id) begin |
rd_autoprech_reg = prev_ba; |
->rd_autoprecharge; |
end |
`endif |
READ_MODE = `FALSE; |
tdata_read <= @(posedge pclk) READ_MODE; // 3.2 |
#0 disable read_block; |
end |
if( WRITE_MODE == `TRUE ) |
begin |
`ifdef M64G3_M128_M256 |
if (auto_flag[prev_ba] == `TRUE && prev_ba != bank_id) begin |
//`ifdef RDL2 |
if (`tRDL == 2) begin |
wr_autoprech_reg2 = prev_ba; |
->wr_autoprecharge2; |
end |
//`else |
else begin |
wr_autoprech_reg = prev_ba; |
->wr_autoprecharge; |
end |
//`endif |
end |
`endif |
WRITE_MODE = `FALSE; |
disable write_block; |
end |
if( |dqm === 1'b0 ) begin // 98.6.26 BYC |
if( CUR_TIME - TDQI < `tSS-`MARGIN ) |
$display("Warning: DQi setup violation at %t", CUR_TIME); |
end |
prev_com = {RASB_FLAG,CASB_FLAG,WEB_FLAG}; |
prev_ba = ba; |
if (pclk_high == last_read) |
rw_dqm <= @(negedge pclk) `TRUE; |
//#0 ->write; |
write_event <= `TRUE; //KyW ... 0408 for VCS |
write_event <= #0.1 `FALSE; //KyW ... 0408 for VCS |
end |
else |
$display("Warning: Illegal write ( %0s is not active) at %t",str,CUR_TIME); |
|
end |
'b110 : // burst stop |
`ifdef DPD |
if( cke === 1'b0 ) |
->deeppowerdown; |
else if (cke === 1'b1) |
`endif |
begin |
`ifdef v $display ("Burst stop"); |
`endif |
|
|
if( READ_MODE == `TRUE ) |
begin |
READ_MODE = `FALSE; |
`ifdef v $display("-- reading burst stop at %t", CUR_TIME); |
`endif |
disable read_block; |
end |
else if( WRITE_MODE == `TRUE) |
begin |
// at this clock, writing done |
`ifdef v $display("-- writing burst stop at %t", CUR_TIME); |
`endif |
`ifdef M16G2_M641G |
WRITE_MODE = @(negedge pclk) `FALSE; |
`else |
WRITE_MODE = `FALSE; |
`endif |
disable write_block; |
end |
prev_com = {RASB_FLAG,CASB_FLAG,WEB_FLAG}; |
end |
'b010 : |
begin |
`endprotect |
`ifdef M16G4_M64G3 //KyW ... 0624 : rev 3.3 |
`else |
if(auto_flagx == `TRUE && (addr[`ADDR_AP] || ba == c_bank_addr)) |
begin |
$display("Warning: Illegal command in auto-precharge command at %t",CUR_TIME); |
disable command_sel; |
end |
`endif |
`ifdef M64_M128_M256 |
`ifdef NBANK2 |
prech_reg[1] = ba; |
prech_reg[0] = addr[`ADDR_AP]; |
`endif |
`ifdef NBANK4 |
prech_reg[2] = ba[1]; |
prech_reg[1] = ba[0]; |
prech_reg[0] = addr[`ADDR_AP]; |
`endif |
`endif |
`ifdef M16 |
prech_reg = addr[11:10]; |
`endif |
->precharge; |
end |
`protect |
'b001 : begin |
if( cke ) |
->autorefresh; |
else if( ~cke ) |
->selfrefresh; |
end |
// default : |
`ifdef v // $display("- NOP"); |
`endif |
endcase |
end // command_sel |
|
// TCLK_H = CUR_TIME; // the time clock is high |
end |
|
`ifdef DPD_PIN |
always @(negedge dpdb) |
if (dpdb === 1'b0) ->deeppowerdown; |
else begin |
`ifdef v $display("Warning: Invalid dpdb pin state at %t", CUR_TIME); |
`endif |
end |
always @(posedge dpdb) |
if (dpdb === 1'b1) begin |
if (D_POWERDOWN == `TRUE) |
begin |
->d_pdown_exit; |
`ifdef v $display(">> deep power down exit at %t", CUR_TIME); |
`endif |
POWERDOWN_MODE = `FALSE; |
CKE_FLAG = `FALSE; |
end |
end |
else begin |
`ifdef v $display("Warning: Invalid dpdb pin state at %t", CUR_TIME); |
`endif |
end |
`endif |
|
// power down or supend enter mode |
always @( posedge pclk ) |
if( POWERDOWN_MODE == `FALSE && cke == `LOW && CUR_TIME - TCKE >= `tSS-`MARGIN ) |
begin |
if( |Mode == 1'b0 ) //BYC |
begin |
`ifdef v $display(">> power down enter at %t",CUR_TIME); |
`endif |
POWERDOWN_MODE = `TRUE; |
end |
else |
begin |
`ifdef v $display(">> clock suspension enter at %t",CUR_TIME); |
`endif |
SUSPEND_MODE = `TRUE; |
end |
end |
|
// clock width check |
always @( negedge clk ) |
if( PWR == `TRUE ) |
begin |
CUR_TIME = $realtime; |
if( CUR_TIME - TCLK_H < `tCH-`MARGIN ) |
$display("Warning: tCH violation at %t", CUR_TIME); |
TCLK_L = CUR_TIME; |
end |
|
// hold time check |
always @(cke) |
begin |
CUR_TIME = $realtime; |
if( PWR == `TRUE ) |
if( POWERDOWN_MODE == `FALSE && CUR_TIME - TCLK_H < `tSH-`MARGIN ) |
$display("Warning: CKE hold violation at %t", CUR_TIME); |
else if( POWERDOWN_MODE == `TRUE && cke == `HIGH ) |
CKE_FLAG = `TRUE; |
|
TCKE = CUR_TIME; |
end |
|
|
always @(addr) //posedge addr or negedge addr ) |
begin |
CUR_TIME = $realtime; |
if( PWR == `TRUE && CSB_FLAG == `LOW && pcke == `HIGH ) |
if( CUR_TIME - TCLK_H < `tSH-`MARGIN ) |
$display("Warning: Address hold violation at %t", CUR_TIME); |
TADDR = CUR_TIME; |
end |
|
always @( negedge rasb or posedge rasb) |
begin |
CUR_TIME = $realtime; |
if( PWR == `TRUE && CSB_FLAG == `LOW ) |
if( pcke == `HIGH && CUR_TIME - TCLK_H < `tSH-`MARGIN ) |
$display("Warning: RASB hold violation at %t", CUR_TIME); |
if(rasb) |
RASB_FLAG = `HIGH; |
TRASB = CUR_TIME; |
end |
|
always @( negedge casb or posedge casb) |
begin |
CUR_TIME = $realtime; |
if( PWR == `TRUE && CSB_FLAG == `LOW ) |
if( pcke == `HIGH && CUR_TIME - TCLK_H < `tSH-`MARGIN ) |
$display("Warning: CASB hold violation at %t", CUR_TIME); |
if(casb) |
CASB_FLAG = `HIGH; |
TCASB = CUR_TIME; |
end |
|
always @( negedge csb or posedge csb) |
begin |
CUR_TIME = $realtime; |
if( csb ) |
CSB_FLAG <= #(CUR_TIME - TCLK_H + `tSH) csb; |
if( PWR == `TRUE && pcke == `HIGH && CUR_TIME - TCLK_H < `tSH-`MARGIN ) |
$display("Warning: CSB hold violation at %t", CUR_TIME); |
TCSB = CUR_TIME; |
end |
|
always @( negedge web or posedge web) |
begin |
CUR_TIME = $realtime; |
if( PWR == `TRUE && CSB_FLAG == `LOW ) |
if( pcke == `HIGH && CUR_TIME - TCLK_H < `tSH-`MARGIN ) |
$display("Warning: WEB hold violation at %t", CUR_TIME); |
if(web) |
WEB_FLAG = `HIGH; |
else |
WEB_FLAG = `LOW; |
TWEB = CUR_TIME; |
end |
|
always @(dqi) |
begin |
if( WRITE_MODE ) |
begin |
CUR_TIME = $realtime; |
if( CUR_TIME - TCLK_H < `tSH-`MARGIN ) |
$display("Warning: DQi hold violation at %t", CUR_TIME); |
end |
TDQI = $realtime; |
end |
|
always @(dqm) begin |
CUR_TIME = $realtime; |
if (PWR == `TRUE) |
for (i = 0; i < `nDQM; i = i + 1) begin |
if (CUR_TIME - TCLK_H < `tSH-`MARGIN && pcke == `HIGH) |
$display("Warning: DQM(%d) hold violation at %t", i, CUR_TIME); |
TDQM[i] = $realtobits(CUR_TIME); |
end |
end |
|
|
/* |
*----------------------------------------------------- |
* power up check routine |
*----------------------------------------------------- |
*/ |
|
initial |
begin |
auto_cnt = -1; |
PWR = `FALSE; |
if(pwrup_check) |
fork |
@(posedge clk or negedge clk) PWR <= #0 `TRUE; |
begin |
#pwrup_time auto_cnt = 0; |
Mode = `INITIAL; |
end |
join |
else |
begin |
@(posedge clk or negedge clk); |
auto_cnt = 2; |
pwrup_done = `TRUE; |
PWR <= #0 `TRUE; |
`ifdef v $display("-- power up check routine skipped"); |
`endif |
end |
end |
|
/* |
*----------------------------------------------------- |
* MRS(mode register set) |
*----------------------------------------------------- |
*/ |
|
always @(modeset) |
begin : mrs_op |
if( &precharge_flag == 1'b1) |
begin |
$display("Warning: Illegal command in precharge operation at %t", CUR_TIME); |
disable mrs_op; |
end |
|
if (|Mode == 1'b0) |
$display(">> MODE register set at %t", CUR_TIME); |
else |
begin |
$display("Warning: Illegal MRS command at %t",CUR_TIME); |
disable mrs_op; |
end |
|
// mode initialization |
MRS_SET = `FALSE; |
|
begin |
if(~|RFU) |
begin // { |
case(addr[2:0]) // burst length programming |
3'b000:begin |
BL = 1; |
WBL = 1; |
$display("-- burst length = 1"); |
end |
3'b001:begin |
BL = 2; |
WBL = 2; |
$display("-- burst length = 2"); |
end |
3'b010:begin |
BL = 4; |
WBL = 4; |
$display("-- burst length = 4"); |
end |
3'b011:begin |
BL = 8; |
WBL = 8; |
$display("-- burst length = 8"); |
end |
3'b111:begin // added |
BL = `PAGEDEPTH; |
WBL = `PAGEDEPTH; |
$display("-- burst length = %d", `PAGEDEPTH); |
end |
default $display("Warning: Invalid Burst length!"); |
endcase |
`endprotect |
|
if(addr[3] && BL != `PAGEDEPTH) // burst type programming |
begin |
burst_type = 1'b1; |
$display("-- burst type = interleave."); |
end |
else |
begin |
`ifdef M16G4_M64G3 // jhkim(8.14) |
if (addr[3] && BL == `PAGEDEPTH) begin |
$display("Warning: interleave mode does not support Full page Mode"); |
$display(" interleave mode will be changed to sequential mode"); |
end |
`endif |
burst_type = 1'b0; |
$display("-- burst type = sequential."); |
end |
|
case(addr[6:4]) // CAS latency programming |
3'b001:begin |
`ifdef NO_CL1 |
$display("Warning: cas latency 1 is not supported in 16M 4Gen. & 64M 3 Gen."); |
`else |
tSAC = `tSAC1; CL=1; tSHZ = `tSHZ1; |
if( TCC_P < `tCC1-`MARGIN ) |
$display("Warning: clock minimun cycle violation at cas latency=1"); |
$display("-- cas latency = 1"); |
`endif |
end |
3'b010:begin |
`ifdef NO_CL2 //KyW |
$display("Warning: cas latency 2 is not supported in this device."); |
`else |
tSAC = `tSAC2; CL=2; tSHZ = `tSHZ2; |
if( TCC_P < `tCC2-`MARGIN ) |
$display("Warning: clock minimun cycle violation at cas latency=2"); |
$display("-- cas latency = 2"); |
`endif |
end |
3'b011:begin |
`ifdef NO_CL3 //KyW |
$display("Warning: cas latency 3 is not supported in this device."); |
`else |
tSAC = `tSAC3; CL=3; tSHZ = `tSHZ3; |
if( TCC_P < `tCC3-`MARGIN ) |
$display("Warning: clock minimun cycle violation at cas latency=3"); |
$display("-- cas latency = 3"); |
`endif |
end |
default $display("Warning: Invalid CAS latency!"); |
endcase |
|
if(addr[9]) |
begin |
$display("-- Burst read single bit write mode"); |
WBL = 1; |
end |
`ifdef NOKIA |
REF16M_MODE = `FALSE; |
REF32M_MODE = `FALSE; |
`endif |
`ifdef MOBILE |
REF4BANK = `TRUE; |
REF2BANK = `FALSE; |
REF1BANK = `FALSE; |
`endif |
end |
`ifdef NOKIA |
else if (addr[8:7] === 2'b01) begin |
if (addr[6:4] === 3'b000) begin |
if (addr[3] === 1'b0) begin |
$display("-- Partial Refresh mode (16M)"); |
REF16M_MODE = `TRUE; |
REF32M_MODE = `FALSE; |
end |
else if (addr[3] === 1'b1) begin |
$display("-- Partial Refresh mode (32M)"); |
REF32M_MODE = `TRUE; |
REF16M_MODE = `FALSE; |
end |
end |
else if (addr[4] === 1'b1) begin |
if (addr[2] === 1'b0) $display("-- VREFi is set to 1.4V"); |
if (addr[2] === 1'b1) $display("-- VREFi is set to 0.9V"); |
end |
end |
`endif |
`ifdef MOBILE |
else if (ba[1] === 1'b1 && ba[0] === 1'b0) begin //Extended MRS for Mobile DRAM |
case(addr[6:5]) // Drive Strength |
2'b00: |
$display("-- Full drive strength"); |
2'b01: |
$display("-- Half drive strength"); |
default $display("Warning: Invalid drive strength address!"); |
endcase |
case(addr[4:3]) // TCSR |
2'b00: |
$display("-- TCSR (46'C~70'C) mode"); |
2'b01: |
$display("-- TCSR (16'C~45'C) mode"); |
2'b10: |
$display("-- TCSR (-25'C~15'C) mode"); |
2'b11: |
$display("-- TCSR (71'C~85'C) mode"); |
default $display("Warning: Invalid TCSR address!"); |
endcase |
case(addr[2:0]) // PASR |
3'b000: begin |
$display("-- PASR (4 banks) mode"); |
REF4BANK = `TRUE; |
REF2BANK = `FALSE; |
REF1BANK = `FALSE; |
end |
3'b001: begin |
$display("-- PASR (2 banks) mode"); |
REF4BANK = `FALSE; |
REF2BANK = `TRUE; |
REF1BANK = `FALSE; |
end |
3'b010: begin |
$display("-- PASR (1 banks) mode"); |
REF4BANK = `FALSE; |
REF2BANK = `FALSE; |
REF1BANK = `TRUE; |
end |
default $display("Warning: Invalid PASR address!"); |
endcase |
end |
`endif |
else |
begin |
$display("-- reserved for future use !!"); |
$display("-- check address: [11,10,8,7] = %b",RFU); |
end |
|
`ifdef M16G4_M64G3 |
MRS_SET <= repeat (2) @(negedge pclk) `TRUE; // From 3 -> 2 |
`else |
MRS_SET <= repeat (2) @(negedge pclk) `TRUE; // From 3 -> 2 |
`endif |
end |
end |
|
`protect |
/* |
*----------------------------------------------------- |
* ACTIVE command |
*----------------------------------------------------- |
*/ |
|
// In active command, bank is selected in accordance with A11 address. |
|
always @(active) |
begin : active_op |
integer bank_id; |
reg [8*8:1] str; |
|
if(CUR_TIME - TRAS_P < `tRRD-`MARGIN) |
begin |
$display("Warning: tRRD violation at %t", CUR_TIME); |
disable active_op; |
end |
|
r_bank_addr = ba; |
|
bank_id = BankSelect(ba); |
str = PrintBank(ba); |
|
//if(CUR_TIME - $bitstoreal(TPRE_P[bank_id]) < `tRP-`MARGIN) |
if ((bank_id == 0) && (CUR_TIME - TPRE_P0 < `tRP-`MARGIN) || |
(bank_id == 1) && (CUR_TIME - TPRE_P1 < `tRP-`MARGIN) || |
(bank_id == 2) && (CUR_TIME - TPRE_P2 < `tRP-`MARGIN) || |
(bank_id == 3) && (CUR_TIME - TPRE_P3 < `tRP-`MARGIN)) |
begin |
$display("Warning: tRP violation at %t", CUR_TIME); |
disable active_op; |
end |
//if(CUR_TIME - $bitstoreal(TRAS_PP[bank_id]) < `tRC-`MARGIN) // 2.27 |
if ((bank_id == 0) && (CUR_TIME - TRAS_PP0 < `tRC-`MARGIN) || |
(bank_id == 1) && (CUR_TIME - TRAS_PP1 < `tRC-`MARGIN) || |
(bank_id == 2) && (CUR_TIME - TRAS_PP2 < `tRC-`MARGIN) || |
(bank_id == 3) && (CUR_TIME - TRAS_PP3 < `tRC-`MARGIN)) |
begin |
$display("Warning: tRC violation at %t", CUR_TIME); |
disable active_op; |
end |
|
if(Mode[bank_id] == `TRUE) |
begin |
$display("Warning: Illegal active (%0s is not precharged) at %t",str,CUR_TIME); |
end |
else |
begin |
/* |
md = Mode; |
md[bank_id] = 1; |
Mode = md; |
*/ |
Mode[bank_id] = 1'b1; |
`ifdef v $display(">> active (%0s) at %t", str, CUR_TIME); |
`endif |
//TRAS_PP[bank_id] = $realtobits(CUR_TIME); // save current time for tRCD,tRC check. |
case(bank_id)//TRAS_PP |
'd0: TRAS_PP0 = CUR_TIME; |
'd1: TRAS_PP1 = CUR_TIME; |
'd2: TRAS_PP2 = CUR_TIME; |
'd3: TRAS_PP3 = CUR_TIME; |
endcase//TRAS_PP |
|
r_addr_[bank_id] = addr[`ADDRTOP:0]; // check in 64M 2bank |
end |
//TRAS_PP[bank_id] = $realtobits(CUR_TIME); // save current time for tRCD,tRC check. |
case(bank_id)//TRAS_PP |
'd0: TRAS_PP0 = CUR_TIME; |
'd1: TRAS_PP1 = CUR_TIME; |
'd2: TRAS_PP2 = CUR_TIME; |
'd3: TRAS_PP3 = CUR_TIME; |
endcase//TRAS_PP |
TRAS_P = CUR_TIME; |
|
end // active operation |
|
/* |
*----------------------------------------------------- |
* READ command |
*----------------------------------------------------- |
*/ |
|
always @(read) |
begin :read_block |
integer bank_id; |
reg [8*8:1] str; |
|
if(CUR_TIME - TCAS_P < `tCCD-`MARGIN) |
begin |
$display("Warning: tCCD violation at %t", CUR_TIME); |
disable read_block; |
end |
|
`ifdef M512_M1024_X4 |
c_addr = {addr[12:11],addr[`nCOL-3:0]}; |
`else |
`ifdef M512_M1024_X8 |
c_addr = {addr[11],addr[`nCOL-2:0]}; |
`else |
`ifdef M128_M256_X4 // 98.6.30 BYC |
c_addr = {addr[11],addr[`nCOL-2:0]}; |
`else |
c_addr = addr[`BIT_C]; |
`endif |
`endif |
`endif |
c_bank_addr = ba; |
|
bank_id = BankSelect(ba); |
str = PrintBank(ba); |
//if(CUR_TIME - $bitstoreal(TRAS_PP[bank_id]) < `tRCD-`MARGIN) |
if ((bank_id == 0) && (CUR_TIME - TRAS_PP0 < `tRCD-`MARGIN) || |
(bank_id == 1) && (CUR_TIME - TRAS_PP1 < `tRCD-`MARGIN) || |
(bank_id == 2) && (CUR_TIME - TRAS_PP2 < `tRCD-`MARGIN) || |
(bank_id == 3) && (CUR_TIME - TRAS_PP3 < `tRCD-`MARGIN)) |
begin |
$display("Warning: tRCD violation at %t", CUR_TIME); |
disable read_block; |
end |
r_addr = r_addr_[bank_id]; |
`endprotect |
|
if(Mode[bank_id] == `TRUE) |
begin |
if( addr[`ADDR_AP] == `TRUE) |
begin |
`ifdef v $display(">> read with auto precharge(%0s) at %t",str,CUR_TIME); |
`endif |
auto_flag[bank_id] <= @(negedge pclk) `TRUE; |
rd_autoprech_reg <= @(negedge pclk) ba; |
end |
else begin |
`ifdef v $display(">> read (%0s) at %t ",str,CUR_TIME); |
`endif |
auto_flag[bank_id] <= @(negedge pclk) `FALSE; |
end |
end |
|
else begin |
`ifdef v $display("Illegal Read %0s is not activated",str); |
`endif |
disable read_block; |
end |
|
READ_MODE = `TRUE; // read operation start |
TCAS_P = CUR_TIME; |
|
m_addr = {r_addr, c_addr}; |
|
if(~burst_type) |
increment_read; |
else |
interleave_read; |
|
`ifdef M16G4_M64G3 |
`else |
if( auto_flag[bank_id] ) |
begin |
if( BL != 1) |
auto_flagx <= @(negedge pclk) `TRUE; |
->autostart; |
end |
`endif |
|
read_task; // task call |
|
READ_MODE = `FALSE; // read operation end. |
// last_rw = CUR_TIME; |
last_rw = TCLK_H; |
|
if( auto_flag[bank_id] ) |
begin |
// rd_autoprech_reg = c_bank_addr; |
if ({CSB_FLAG,RASB_FLAG,CASB_FLAG} == 3'b010 && bank_id === ba) |
$display($time, " Warning: For actual device, this gapless command would be illegal"); |
else |
->rd_autoprecharge; |
end |
end |
|
/* |
*----------------------------------------------------- |
* WRITE command |
*----------------------------------------------------- |
*/ |
|
//always @(write) |
always @(posedge write_event)//KyW ... 0408 for VCS |
begin:write_block |
integer bank_id; |
reg [8*8:1] str; |
|
if(CUR_TIME - TCAS_P < `tCCD-`MARGIN) |
begin |
$display("Warning: tCCD violation at %t", CUR_TIME); |
disable write_block; |
end |
|
`ifdef M512_X4 |
c_addr = {addr[12:11],addr[`nCOL-3:0]}; |
`else |
`ifdef M512_X8 |
c_addr = {addr[11],addr[`nCOL-2:0]}; |
`else |
`ifdef M128_M256_X4 // 98.6.30 BYC |
c_addr = {addr[11],addr[`nCOL-2:0]}; |
`else |
c_addr = addr[`BIT_C]; |
`endif |
`endif |
`endif |
c_bank_addr = ba; |
|
bank_id = BankSelect(ba); |
str = PrintBank(ba); |
r_addr = r_addr_[bank_id]; |
|
//if(CUR_TIME - $bitstoreal(TRAS_PP[bank_id]) < `tRCD-`MARGIN) |
if ((bank_id == 0) && (CUR_TIME - TRAS_PP0 < `tRCD-`MARGIN) || |
(bank_id == 1) && (CUR_TIME - TRAS_PP1 < `tRCD-`MARGIN) || |
(bank_id == 2) && (CUR_TIME - TRAS_PP2 < `tRCD-`MARGIN) || |
(bank_id == 3) && (CUR_TIME - TRAS_PP3 < `tRCD-`MARGIN)) |
begin |
$display("Warning: tRCD violation at %t", CUR_TIME); |
disable write_block; |
end |
|
if(Mode[bank_id] == `TRUE) |
begin |
if(addr[`ADDR_AP]) |
begin |
`ifdef v $display(">> write with auto precharge( %0s ) at %t",str,CUR_TIME); |
`endif |
auto_flag[bank_id] <= @(negedge pclk) `TRUE; |
//`ifdef RDL2 |
if (`tRDL == 2) |
wr_autoprech_reg2 <= @(negedge pclk) ba; |
//`else |
else |
wr_autoprech_reg <= @(negedge pclk) ba; |
//`endif |
end |
else begin |
`ifdef v $display(">> write ( %0s ) at %t",str,CUR_TIME); |
`endif |
auto_flag[bank_id] <= @(negedge pclk) `FALSE; |
/* |
if (auto_flag == `TRUE && autoprech_reg == ba) |
auto_flag = `FALSE; |
*/ |
end |
end |
else |
begin |
$display("Warning: Illegal write command at %t",CUR_TIME); |
disable write_block; |
end |
|
WRITE_MODE = `TRUE; |
TCAS_P = CUR_TIME; |
|
m_addr = {r_addr, c_addr}; |
|
`ifdef M16G4_M64G3 |
`else |
if( auto_flag[bank_id] ) |
begin |
if( WBL != 1) |
auto_flagx <= @(negedge pclk) `TRUE; |
->autostart; |
end |
`endif |
|
write_task; |
|
WRITE_MODE <= #(`tSH) `FALSE; |
last_rw = CUR_TIME; |
|
@(posedge pclk); |
if(auto_flag[bank_id]) begin |
if ({CSB_FLAG,RASB_FLAG,CASB_FLAG} == 3'b010 && bank_id === ba) |
$display($time, " Warning: For actual device, this gapless command would be illegal"); |
else begin |
//`ifdef RDL2 |
if (`tRDL == 2) |
#0 ->wr_autoprecharge2; |
//`else |
else |
->wr_autoprecharge; |
//`endif |
end |
end |
end |
|
`protect |
// In bank interleave write mode, din data should be stored |
// in din register as the other bank selection occurred. |
|
always @(flush_write) |
begin |
if(~burst_type) |
increment_write; |
else |
interleave_write; |
end |
|
/* |
*----------------------------------------------------- |
* REFRESH command |
*----------------------------------------------------- |
*/ |
|
always @(autorefresh) |
begin : auto_op |
if (INIT == `FALSE && MRS_SET == `FALSE) // for refersh protection during MRS_ING |
begin |
$display("Warning: Illegal refresh command at %t",CUR_TIME); |
disable auto_op; |
end |
|
if (|Mode !== 1'b0) begin |
$display("Warning: Illegal refresh command at %t",CUR_TIME); |
disable auto_op; |
end |
|
/* -- jhkim-TEST |
`ifdef M16G4_M64G3 |
`else |
for(i=0; i < `nBank; i=i+1) |
begin |
//if( CUR_TIME - $bitstoreal(TRAS_PP[i]) < `tRFC-`MARGIN ) |
if ((i == 0) && (CUR_TIME - TRAS_PP0 < `tRFC-`MARGIN) || |
(i == 1) && (CUR_TIME - TRAS_PP1 < `tRFC-`MARGIN) || |
(i == 2) && (CUR_TIME - TRAS_PP2 < `tRFC-`MARGIN) || |
(i == 3) && (CUR_TIME - TRAS_PP3 < `tRFC-`MARGIN)) |
$display("Warning: tRFC violation at %t",CUR_TIME); |
end |
`endif |
*/ |
|
AUTOREF_MODE = `TRUE; |
`ifdef v |
//`ifdef NOKIA |
// if (REF16M_MODE == `TRUE) |
// $display(">> partial auto refresh (16M) at %t",CUR_TIME); |
// else if (REF32M_MODE == `TRUE) |
// $display(">> partial auto refresh (32M) at %t",CUR_TIME); |
// else |
//`endif |
$display(">> auto refresh at %t",CUR_TIME); |
`endif |
/* -- jhkim-TEST |
`ifdef M16G4_M64G3 |
AUTOREF_MODE = #(`tRC) `FALSE; |
`else |
AUTOREF_MODE = #(`tRFC) `FALSE; |
`endif |
*/ |
`ifdef tARFC |
AUTOREF_MODE = #(`tARFC) `FALSE; |
`else |
AUTOREF_MODE = #(`tRC) `FALSE; |
`endif |
|
end |
|
/* |
*----------------------------------------------------- |
* SELF REFRESH command |
*----------------------------------------------------- |
*/ |
|
always @(selfrefresh) |
begin : self_op |
if (|Mode == 1'b0) begin |
SELFREF_MODE = `TRUE; |
`ifdef v |
`ifdef NOKIA |
if (REF16M_MODE == `TRUE) |
$display(">> partial self refresh (16M) enter at %t",CUR_TIME); |
else if (REF32M_MODE == `TRUE) |
$display(">> partial self refresh (32M) enter at %t",CUR_TIME); |
else |
`endif |
`ifdef MOBILE |
if (REF4BANK == `TRUE) |
$display(">> Partial Array Self Refresh (4banks) enter at %t",CUR_TIME); |
else if (REF2BANK == `TRUE) |
$display(">> Partial Array Self Refresh (2banks) enter at %t",CUR_TIME); |
else if (REF1BANK == `TRUE) |
$display(">> Partial Array Self Refresh (1banks) enter at %t",CUR_TIME); |
else |
`endif |
$display(">> self refresh enter at %t",CUR_TIME); |
`endif |
TSELF = CUR_TIME; |
end |
else begin |
$display("Warning: Illegal self refresh command at %t",CUR_TIME); |
disable self_op; |
end |
|
for(i =0; i < `nBank; i = i+1) |
begin |
/* -- jhkim-TEST |
`ifdef M16G4_M64G3 |
//if( CUR_TIME - $bitstoreal(TRAS_PP[i]) < `tRC-`MARGIN ) |
if ((i == 0) && (CUR_TIME - TRAS_PP0 < `tRC-`MARGIN) || |
(i == 1) && (CUR_TIME - TRAS_PP1 < `tRC-`MARGIN) || |
(i == 2) && (CUR_TIME - TRAS_PP2 < `tRC-`MARGIN) || |
(i == 3) && (CUR_TIME - TRAS_PP3 < `tRC-`MARGIN)) |
$display("Warning: tRC violation at %t",CUR_TIME); |
`else |
//if( CUR_TIME - $bitstoreal(TRAS_PP[i]) < `tRFC-`MARGIN ) |
if ((i == 0) && (CUR_TIME - TRAS_PP0 < `tRFC-`MARGIN) || |
(i == 1) && (CUR_TIME - TRAS_PP1 < `tRFC-`MARGIN) || |
(i == 2) && (CUR_TIME - TRAS_PP2 < `tRFC-`MARGIN) || |
(i == 3) && (CUR_TIME - TRAS_PP3 < `tRFC-`MARGIN)) |
$display("Warning: tRFC violation at %t",CUR_TIME); |
`endif |
*/ |
//if( CUR_TIME - $bitstoreal(TRAS_PP[i]) < `tRC-`MARGIN ) |
if ((i == 0) && (CUR_TIME - TRAS_PP0 < `tRC-`MARGIN) || |
(i == 1) && (CUR_TIME - TRAS_PP1 < `tRC-`MARGIN) || |
(i == 2) && (CUR_TIME - TRAS_PP2 < `tRC-`MARGIN) || |
(i == 3) && (CUR_TIME - TRAS_PP3 < `tRC-`MARGIN)) |
$display("Warning: tRC violation at %t",CUR_TIME); |
end |
end |
|
always @(selfexit) begin |
TSEXIT = CUR_TIME; |
/* -- jhkim-TEST |
`ifdef M16G4_M64G3 |
SELFREF_MODE = #(`tRC) `FALSE; |
`else |
SELFREF_MODE = #(`tRFC) `FALSE; |
`endif |
*/ |
`ifdef tSRFX |
SELFREF_MODE = #(`tSRFX) `FALSE; |
`else |
SELFREF_MODE = #(`tRC) `FALSE; |
`endif |
end |
|
/* |
always @(negedge cke) begin |
if (SELFREF_MODE == `TRUE && POWERDOWN_MODE == `FALSE) begin |
if (CUR_TIME - TSEXIT < `tSRX-`MARGIN) |
$display("Warning: tSRX violation at %t", CUR_TIME); |
end |
end |
*/ |
`endprotect |
|
/* |
*----------------------------------------------------- |
* PRECHARGE command |
*----------------------------------------------------- |
*/ |
|
// precharge command performs to disable active operation. |
|
always @(precharge) |
begin : prech_op |
integer bank_id; |
integer i; |
reg [8*8:1] str; |
reg [8*8:1] str1; |
|
`ifdef NBANK4 |
bank_id = BankSelect(prech_reg[2:1]); |
str = PrintBank(prech_reg[2:1]); |
`endif |
`ifdef NBANK2 |
bank_id = BankSelect(prech_reg[1]); |
str = PrintBank(prech_reg[1]); |
`endif |
`protect |
|
if(prech_reg[0] == `FALSE) |
begin |
|
if(Mode[bank_id] !== 1'b0) |
begin |
|
//if(CUR_TIME - $bitstoreal(TRAS_PP[bank_id]) < `tRASmin-`MARGIN) |
if ((bank_id == 0) && (CUR_TIME - TRAS_PP0 < `tRASmin-`MARGIN) || |
(bank_id == 1) && (CUR_TIME - TRAS_PP1 < `tRASmin-`MARGIN) || |
(bank_id == 2) && (CUR_TIME - TRAS_PP2 < `tRASmin-`MARGIN) || |
(bank_id == 3) && (CUR_TIME - TRAS_PP3 < `tRASmin-`MARGIN)) |
begin |
$display("Warning: tRASmin violation( %0s ) at %t", str, CUR_TIME); |
disable prech_op; |
end |
|
//if(first_pre[bank_id]==`FALSE && CUR_TIME - $bitstoreal(TRAS_PP[bank_id]) > `tRASmax+`MARGIN) |
if (first_pre[bank_id]==`FALSE && ((bank_id == 0) && (CUR_TIME - TRAS_PP0 > `tRASmax-`MARGIN) || |
(bank_id == 1) && (CUR_TIME - TRAS_PP1 > `tRASmax-`MARGIN) || |
(bank_id == 2) && (CUR_TIME - TRAS_PP2 > `tRASmax-`MARGIN) || |
(bank_id == 3) && (CUR_TIME - TRAS_PP3 > `tRASmax-`MARGIN))) |
$display("Warning: tRASmax violation( %0s ) at %t", str, CUR_TIME); |
|
first_pre[bank_id] = `FALSE; |
|
md = Mode; |
md[bank_id] = 0; |
Mode = md; |
`ifdef v $display(">> precharge ( %0s ) at %t", str, CUR_TIME); |
`endif |
end |
|
else |
begin |
`ifdef v $display("-- current precharge command is NOP at %t",CUR_TIME); |
`endif |
disable prech_op; |
end |
|
precharge_flag[bank_id] = `TRUE; |
kill_bank = bank_id; |
->precharge_flag_kill; |
//TPRE_P[bank_id] = $realtobits(CUR_TIME); |
case(bank_id)//TPRE_P |
'd0: TPRE_P0 = CUR_TIME; |
'd1: TPRE_P1 = CUR_TIME; |
'd2: TPRE_P2 = CUR_TIME; |
'd3: TPRE_P3 = CUR_TIME; |
endcase//TPRE_P |
end |
|
else |
begin |
if(|Mode[`nBank-1:0] !== 1'b0) // BYC |
begin |
|
for(i = 0; i < `nBank; i = i+1) |
begin |
case(i) |
'd0 : |
str1 = " A Bank"; |
'd2 : |
str1 = " B Bank"; |
'd1 : |
str1 = " C Bank"; |
'd3 : |
str1 = " D Bank"; |
default : |
str1 = "Bad Bank"; |
endcase |
|
//if(Mode[i] !== 1'b0 && CUR_TIME - $bitstoreal(TRAS_PP[i]) < `tRASmin-`MARGIN) |
if (Mode[i] !== 1'b0 && ((i == 0) && (CUR_TIME - TRAS_PP0 < `tRASmin-`MARGIN) || |
(i == 1) && (CUR_TIME - TRAS_PP1 < `tRASmin-`MARGIN) || |
(i == 2) && (CUR_TIME - TRAS_PP2 < `tRASmin-`MARGIN) || |
(i == 3) && (CUR_TIME - TRAS_PP3 < `tRASmin-`MARGIN))) |
begin |
$display("Warning: tRASmin violation ( %0s ) at %t", str1, CUR_TIME); |
disable prech_op; |
end |
|
//if(Mode[i] !== 1'b0 && first_pre[i]==`FALSE && CUR_TIME - $bitstoreal(TRAS_PP[i]) > `tRASmax+`MARGIN) |
if (Mode[i] !== 1'b0 && first_pre[i]==`FALSE && ((i == 0) && (CUR_TIME - TRAS_PP0 > `tRASmax-`MARGIN) || |
(i == 1) && (CUR_TIME - TRAS_PP1 > `tRASmax-`MARGIN) || |
(i == 2) && (CUR_TIME - TRAS_PP2 > `tRASmax-`MARGIN) || |
(i == 3) && (CUR_TIME - TRAS_PP3 > `tRASmax-`MARGIN))) |
$display("Warning: tRASmax violation ( %0s ) at %t", str1, CUR_TIME); |
|
first_pre[i] = `FALSE; |
|
Mode[i] = 1'b0; |
precharge_flag[i] = `TRUE; |
//TPRE_P[i] = $realtobits(CUR_TIME); |
case(i)//TPRE_P |
'd0: TPRE_P0 = CUR_TIME; |
'd1: TPRE_P1 = CUR_TIME; |
'd2: TPRE_P2 = CUR_TIME; |
'd3: TPRE_P3 = CUR_TIME; |
endcase//TPRE_P |
first_pre[i] = `FALSE; |
end |
|
`ifdef NBANK2 |
`ifdef v $display(">> precharge ( A and B bank ) at %t",CUR_TIME); |
`endif |
`endif |
`ifdef NBANK4 |
`ifdef v $display(">> precharge ( A,B,C, and D bank ) at %t",CUR_TIME); |
`endif |
`endif |
end |
|
else |
begin |
`ifdef v $display("-- current precharge command is NOP at %t",CUR_TIME); |
`endif |
disable prech_op; |
end |
|
kill_bank = bank_id; |
->precharge_flag_kill; |
|
end |
->precharge_start; |
end |
`endprotect |
|
/* |
*----------------------------------------------------- |
* tRDL=2 AUTO PRECHARGE command |
*----------------------------------------------------- |
*/ |
|
always @(wr_autoprecharge2) begin |
wr_autoprech_reg = wr_autoprech_reg2; |
@(posedge pclk); |
if ({CSB_FLAG,RASB_FLAG,CASB_FLAG} == 3'b010 && wr_autoprech_reg === ba) |
$display($time, " Warning: For actual device, this 1-clk-gap command would be illegal"); |
else |
->wr_autoprecharge; |
end |
|
/* |
*----------------------------------------------------- |
* READ AUTO PRECHARGE command |
*----------------------------------------------------- |
*/ |
|
always @(rd_autoprecharge or posedge rd_reautoprecharge) |
begin : rd_autoprech_op |
real difftime; |
integer bank_id; |
reg [8*8:1] str; |
reg tmp_reauto; |
integer prev_bank; |
integer tmp_bank; |
|
tmp_reauto = `FALSE; |
bank_id = BankSelect(rd_autoprech_reg); |
if (rd_reautoprecharge == `TRUE) begin |
rd_reautoprecharge = `FALSE; |
tmp_bank = prev_bank; |
end |
else |
tmp_bank = bank_id; |
str = PrintBank(tmp_bank); |
//difftime = $realtime - $bitstoreal(TRAS_PP[tmp_bank]); |
case(tmp_bank)//TRAS_PP |
'd0: difftime = $realtime-TRAS_PP0; |
'd1: difftime = $realtime-TRAS_PP1; |
'd2: difftime = $realtime-TRAS_PP2; |
'd3: difftime = $realtime-TRAS_PP3; |
endcase//TRAS_PP |
if(difftime < `tRASmin-`MARGIN) |
begin |
`ifdef M64G3_M128_M256 |
//auto_flagx <= `TRUE; // KyW ... 0624 : rev 3.3 |
//auto_flagx <= #(`tRASmin-difftime) `FALSE; // KyW ... 0624 : rev 3.3 |
prev_bank <= #(`tRASmin-difftime) tmp_bank; |
rd_reautoprecharge <= #(`tRASmin-difftime) `TRUE; |
tmp_reauto = `TRUE; |
`ifdef v $display(" Info: Staring Auto precharge (%s) delayed by tRASmin violation at %t", str, $time); |
`endif |
// #0 disable rd_autoprech_op; |
`else |
rd_reautoprecharge = `FALSE; |
$display("Warning: tRASmin violation at %t", $realtime); |
disable rd_autoprech_op; |
`endif |
end |
if(difftime > `tRASmax+`MARGIN) |
begin |
$display("Warning: tRASmax violation at %t", $realtime); |
end |
|
`ifdef M16G4_M64G3 |
if (tmp_reauto == `FALSE) begin |
`endif |
`ifdef v $display(">> auto precharge ( %0s) at %t", str, $realtime); |
`endif |
Mode[tmp_bank] = 0; |
|
precharge_flag[tmp_bank] = `TRUE; |
rd_kill_bank = tmp_bank; |
->rd_precharge_flag_kill; |
//TPRE_P[tmp_bank] = $realtobits($realtime); |
case(tmp_bank)//TPRE_P |
'd0: TPRE_P0 = $realtime; |
'd1: TPRE_P1 = $realtime; |
'd2: TPRE_P2 = $realtime; |
'd3: TPRE_P3 = $realtime; |
endcase//TPRE_P |
`ifdef M16G4_M64G3 |
end |
`endif |
end |
|
/* |
*----------------------------------------------------- |
* WRITE AUTO PRECHARGE command |
*----------------------------------------------------- |
*/ |
|
always @(wr_autoprecharge or posedge wr_reautoprecharge) |
begin : wr_autoprech_op |
real difftime; |
integer bank_id; |
reg [8*8:1] str; |
reg tmp_reauto; |
integer prev_bank; |
integer tmp_bank; |
|
tmp_reauto = `FALSE; |
bank_id = BankSelect(wr_autoprech_reg); |
if (wr_reautoprecharge == `TRUE) begin |
wr_reautoprecharge = `FALSE; |
tmp_bank = prev_bank; |
end |
else |
tmp_bank = bank_id; |
str = PrintBank(tmp_bank); |
//difftime = $realtime - $bitstoreal(TRAS_PP[tmp_bank]); |
case(tmp_bank)//TRAS_PP |
'd0: difftime = $realtime-TRAS_PP0; |
'd1: difftime = $realtime-TRAS_PP1; |
'd2: difftime = $realtime-TRAS_PP2; |
'd3: difftime = $realtime-TRAS_PP3; |
endcase//TRAS_PP |
if(difftime < `tRASmin-`MARGIN) |
begin |
`ifdef M64G3_M128_M256 |
//auto_flagx <= `TRUE; // KyW ... 0624 : rev 3.3 |
//auto_flagx <= #(`tRASmin-difftime) `FALSE; // KyW ... 0624 : rev 3.3 |
prev_bank <= #(`tRASmin-difftime) tmp_bank; |
wr_reautoprecharge <= #(`tRASmin-difftime) `TRUE; |
tmp_reauto = `TRUE; |
`ifdef v $display(" Info: Staring Auto precharge (%s) delayed by tRASmin violation at %t", str, $time); |
`endif |
// #0 disable wr_autoprech_op; |
`else |
wr_reautoprecharge = `FALSE; |
$display("Warning: tRASmin violation at %t", $realtime); |
disable wr_autoprech_op; |
`endif |
end |
if(difftime > `tRASmax+`MARGIN) |
begin |
$display("Warning: tRASmax violation at %t", $realtime); |
end |
|
`ifdef M16G4_M64G3 |
if (tmp_reauto == `FALSE) begin |
`endif |
`ifdef v $display(">> auto precharge ( %0s) at %t", str, $realtime); |
`endif |
Mode[tmp_bank] = 0; |
|
precharge_flag[tmp_bank] = `TRUE; |
wr_kill_bank = tmp_bank; |
->wr_precharge_flag_kill; |
//TPRE_P[tmp_bank] = $realtobits($realtime); |
case(tmp_bank)//TPRE_P |
'd0: TPRE_P0 = $realtime; |
'd1: TPRE_P1 = $realtime; |
'd2: TPRE_P2 = $realtime; |
'd3: TPRE_P3 = $realtime; |
endcase//TPRE_P |
`ifdef M16G4_M64G3 |
end |
`endif |
end |
|
/* |
*----------------------------------------------------- |
*/ |
|
always @(autostart) |
begin |
if( READ_MODE ) |
begin |
auto_flagx = repeat (BL) @(negedge pclk) `FALSE; |
end |
else if( WRITE_MODE ) |
begin |
auto_flagx = repeat (WBL) @(negedge pclk) `FALSE; |
end |
end |
/* |
*----------------------------------------------------- |
* DEEP POWER DOWN |
*----------------------------------------------------- |
*/ |
`ifdef DPD |
always @(deeppowerdown) |
begin : d_powerdown |
if (|Mode == 1'b0) begin |
D_POWERDOWN = `TRUE; |
`ifdef v |
$display(">> Deep power down enter at %t",CUR_TIME); |
`endif |
end |
else begin |
$display("Warning: Illegal deep power down command at %t",CUR_TIME); |
disable d_powerdown; |
end |
end |
|
always @(d_pdown_exit) begin |
D_POWERDOWN <= #(`tDPDEXIT-`MARGIN) `FALSE; |
D_PDOWN_EXIT <= #(`tDPDEXIT-`MARGIN) `TRUE; |
end |
`endif |
|
/* |
*----------------------------------------------------- |
* move memory data to dout register |
* by sequential counter |
*----------------------------------------------------- |
*/ |
|
// This task models behavior of increment counter |
// Simply, address is increased by one and one. |
|
task increment_read; |
begin:ir |
integer j,s,t; |
integer bank; |
reg [`BIT_T] maddr; |
reg [`BIT_C] check_111; |
|
bank = BankSelect(c_bank_addr); |
|
maddr = m_addr; |
for(j=0; j<= BL-1; j=j+1) begin |
|
case(bank) |
'd0: begin |
`ifdef DYMEM |
$damem_read("mem_a", maddr, dout_reg[j]); |
$damem_read("mem_a", maddr, din_rega[j]); |
`else |
dout_reg[j] = mem_a[maddr]; |
din_rega[j] = mem_a[maddr]; |
`endif |
end |
'd1: begin |
`ifdef DYMEM |
`ifdef MOBILE |
if (REF1BANK == `TRUE) dout_reg[j] = `B'bx; |
else |
$damem_read("mem_b", maddr, dout_reg[j]); |
`else |
$damem_read("mem_b", maddr, dout_reg[j]); |
`endif |
$damem_read("mem_b", maddr, din_regb[j]); |
`else |
`ifdef MOBILE |
if (REF1BANK == `TRUE) dout_reg[j] = `B'bx; |
else |
dout_reg[j] = mem_b[maddr]; |
`else |
dout_reg[j] = mem_b[maddr]; |
`endif |
din_regb[j] = mem_b[maddr]; |
`endif |
end |
`ifdef NBANK4 |
'd2: begin |
`ifdef DYMEM |
`ifdef MOBILE |
if (REF4BANK == `FALSE) dout_reg[j] = `B'bx; |
else |
$damem_read("mem_c", maddr, dout_reg[j]); |
`else |
$damem_read("mem_c", maddr, dout_reg[j]); |
`endif |
$damem_read("mem_c", maddr, din_regc[j]); |
`else |
`ifdef MOBILE |
if (REF4BANK == `FALSE) dout_reg[j] = `B'bx; |
else |
dout_reg[j] = mem_c[maddr]; |
`else |
dout_reg[j] = mem_c[maddr]; |
`endif |
din_regc[j] = mem_c[maddr]; |
`endif |
end |
'd3: begin |
`ifdef DYMEM |
`ifdef MOBILE |
if (REF4BANK == `FALSE) dout_reg[j] = `B'bx; |
else |
$damem_read("mem_d", maddr, dout_reg[j]); |
`else |
$damem_read("mem_d", maddr, dout_reg[j]); |
`endif |
$damem_read("mem_d", maddr, din_regd[j]); |
`else |
`ifdef MOBILE |
if (REF4BANK == `FALSE) dout_reg[j] = `B'bx; |
else |
dout_reg[j] = mem_d[maddr]; |
`else |
dout_reg[j] = mem_d[maddr]; |
`endif |
din_regd[j] = mem_d[maddr]; |
`endif |
end |
`endif |
endcase |
|
case(BL) |
'd1: begin |
end |
'd2: maddr[0] = ~maddr[0]; |
'd4: begin |
check_111 = m_addr + j+1; |
maddr[1:0] = check_111[1:0]; |
end |
'd8: begin |
check_111 = m_addr + j+1; |
maddr[2:0] = check_111[2:0]; |
end |
`PAGEDEPTH: begin // case 256 |
check_111 = m_addr + j+1; |
maddr[`BIT_C] = check_111[`BIT_C]; |
end |
default: begin |
$display("Warning: burst length is out of spec"); |
disable increment_read; |
end |
endcase |
end // end of for loop |
|
end |
endtask |
|
/* |
*----------------------------------------------------- |
* move memory data to dout register |
* by interleave counter |
*----------------------------------------------------- |
*/ |
|
// Interleave counting mechanism is different from |
// sequential method. Counting step could be varied with |
// initial address.(refer to data sheet) |
|
task interleave_read; |
begin:ir1 |
integer j; |
integer bank; |
reg [`BIT_T] maddr; |
|
bank = BankSelect(c_bank_addr); |
maddr = m_addr; |
for(j=0; j<=BL-1; j=j+1) begin |
case(bank) |
'd0: begin |
`ifdef DYMEM |
$damem_read("mem_a", maddr, dout_reg[j]); |
$damem_read("mem_a", maddr, din_rega[j]); |
`else |
dout_reg[j] = mem_a[maddr]; |
din_rega[j] = mem_a[maddr]; |
`endif |
end |
'd1: begin |
`ifdef DYMEM |
`ifdef MOBILE |
if (REF1BANK == `TRUE) dout_reg[j] = `B'bx; |
else |
$damem_read("mem_b", maddr, dout_reg[j]); |
`else |
$damem_read("mem_b", maddr, dout_reg[j]); |
`endif |
$damem_read("mem_b", maddr, din_regb[j]); |
`else |
`ifdef MOBILE |
if (REF1BANK == `TRUE) dout_reg[j] = `B'bx; |
else |
dout_reg[j] = mem_b[maddr]; |
`else |
dout_reg[j] = mem_b[maddr]; |
`endif |
din_regb[j] = mem_b[maddr]; |
`endif |
end |
`ifdef NBANK4 |
'd2: begin |
`ifdef DYMEM |
`ifdef MOBILE |
if (REF4BANK == `FALSE) dout_reg[j] = `B'bx; |
else |
$damem_read("mem_c", maddr, dout_reg[j]); |
`else |
$damem_read("mem_c", maddr, dout_reg[j]); |
`endif |
$damem_read("mem_c", maddr, din_regc[j]); |
`else |
`ifdef MOBILE |
if (REF4BANK == `FALSE) dout_reg[j] = `B'bx; |
else |
dout_reg[j] = mem_c[maddr]; |
`else |
dout_reg[j] = mem_c[maddr]; |
`endif |
din_regc[j] = mem_c[maddr]; |
`endif |
end |
'd3: begin |
`ifdef DYMEM |
`ifdef MOBILE |
if (REF4BANK == `FALSE) dout_reg[j] = `B'bx; |
else |
$damem_read("mem_d", maddr, dout_reg[j]); |
`else |
$damem_read("mem_d", maddr, dout_reg[j]); |
`endif |
$damem_read("mem_d", maddr, din_regd[j]); |
`else |
`ifdef MOBILE |
if (REF4BANK == `FALSE) dout_reg[j] = `B'bx; |
else |
dout_reg[j] = mem_d[maddr]; |
`else |
dout_reg[j] = mem_d[maddr]; |
`endif |
din_regd[j] = mem_d[maddr]; |
`endif |
end |
`endif |
endcase |
|
case(BL) |
'd1:begin |
end |
'd2: |
maddr[0] = ~maddr[0]; |
'd4: begin |
if( j == 0 || j == 2) |
maddr[0] = ~maddr[0]; |
else |
maddr[1:0] = ~maddr[1:0]; |
end |
'd8: begin |
if(j == 0 || j == 2 || j == 4 || j==6) |
maddr[0] = ~maddr[0]; |
else if(j == 1 || j == 5) |
maddr[1:0] = ~maddr[1:0]; |
else |
maddr[2:0] = ~maddr[2:0]; |
end |
default: $display("Warning: burst length is out of spec."); |
endcase |
end |
end |
endtask |
|
/* |
*----------------------------------------------------- |
* move memory data to din register array |
* by sequential counter |
*----------------------------------------------------- |
*/ |
|
task increment_write; |
begin:iw |
integer j,s,t; |
reg [`BIT_T] maddr; |
reg [`BIT_C] check_111; |
integer bank; |
|
bank = BankSelect(c_bank_addr); |
maddr = m_addr; |
for(j=0; j<=WBL-1; j=j+1) begin |
case(bank) |
'd0: |
`ifdef DYMEM |
$damem_write("mem_a", maddr, din_rega[j]); |
`else |
mem_a[maddr] = din_rega[j]; |
`endif |
'd1: |
`ifdef DYMEM |
$damem_write("mem_b", maddr, din_regb[j]); |
`else |
mem_b[maddr] = din_regb[j]; |
`endif |
`ifdef NBANK4 |
'd2: |
`ifdef DYMEM |
$damem_write("mem_c", maddr, din_regc[j]); |
`else |
mem_c[maddr] = din_regc[j]; |
`endif |
'd3: |
`ifdef DYMEM |
$damem_write("mem_d", maddr, din_regd[j]); |
`else |
mem_d[maddr] = din_regd[j]; |
`endif |
`endif |
endcase |
case(WBL) |
'd1: begin |
end |
'd2: |
maddr[0] = ~maddr[0]; |
'd4: begin |
check_111 = m_addr +j+1; |
maddr[1:0] = check_111[1:0]; |
end |
'd8: begin |
check_111 = m_addr +j+1; |
maddr[2:0] = check_111[2:0]; |
end |
`PAGEDEPTH: begin |
check_111 = m_addr +j+1; |
maddr[`BIT_C] = check_111[`BIT_C]; |
end |
default: begin |
$display("Warning: burst length is out of spec"); |
disable increment_write; |
end |
endcase |
end |
end |
endtask |
|
/* |
*----------------------------------------------------- |
* move memory data to din register array |
* by interleave counter |
*----------------------------------------------------- |
*/ |
|
task interleave_write; |
begin:iw1 |
integer j; |
integer bank; |
reg [`BIT_T] maddr; |
|
bank = BankSelect(c_bank_addr); |
maddr = m_addr; |
for(j=0; j <= WBL-1; j=j+1) begin |
case(bank) |
'd0: |
`ifdef DYMEM |
$damem_write("mem_a", maddr, din_rega[j]); |
`else |
mem_a[maddr] = din_rega[j]; |
`endif |
'd1: |
`ifdef DYMEM |
$damem_write("mem_b", maddr, din_regb[j]); |
`else |
mem_b[maddr] = din_regb[j]; |
`endif |
`ifdef NBANK4 |
'd2: |
`ifdef DYMEM |
$damem_write("mem_c", maddr, din_regc[j]); |
`else |
mem_c[maddr] = din_regc[j]; |
`endif |
'd3: |
`ifdef DYMEM |
$damem_write("mem_d", maddr, din_regd[j]); |
`else |
mem_d[maddr] = din_regd[j]; |
`endif |
`endif |
endcase |
case(WBL) |
'd1:begin |
end |
'd2: |
maddr[0] = ~maddr[0]; |
'd4: begin |
if((j % 2) == 0) |
maddr[0] = ~maddr[0]; |
else |
maddr[1:0] = ~maddr[1:0]; |
end |
'd8: begin |
if((j % 2) == 0) |
maddr[0] = ~maddr[0]; |
else if(j == 1 || j == 5) |
maddr[1:0] = ~maddr[1:0]; |
else |
maddr[2:0] = ~maddr[2:0]; |
end |
default: |
begin |
$display("Warning: burst length is out of spec."); |
end |
endcase |
end |
end |
endtask |
|
`protect |
|
/* |
*----------------------------------------------------- |
* precharge interrupt |
*----------------------------------------------------- |
*/ |
always @(precharge_start) |
begin: pc_start |
integer bank_id; |
reg [8*8:1] str; |
|
if( READ_MODE == `TRUE ) |
begin |
bank_id = BankSelect(c_bank_addr); |
str = PrintBank(c_bank_addr); |
if(precharge_flag[bank_id]) |
begin |
`ifdef v $display("-- read operation interrupted by precharge"); |
`endif |
READ_MODE = `FALSE; |
disable read_block; |
end |
end |
if( WRITE_MODE == `TRUE ) |
begin |
bank_id = BankSelect(c_bank_addr); |
str = PrintBank(c_bank_addr); |
if(precharge_flag[bank_id]) |
begin |
`ifdef v $display("-- write operation interrupted by precharge"); |
`endif |
for (i = 0; i < `nDQM; i = i + 1) begin : dqm_high_check |
if(dqm[i] == `FALSE) begin |
`ifdef v $display(" DQM must be high at %t", CUR_TIME); |
`endif |
i = `nDQM; |
end |
end |
WRITE_MODE = `FALSE; |
disable write_block; |
end |
end |
end |
|
always @(precharge_flag_kill) begin |
if (prech_reg[0] == `TRUE) begin |
for (i = 0; i < `nBank; i = i+1) |
precharge_flag[i] <= #(`tRP-1) `FALSE; |
end |
else begin |
if( precharge_flag[kill_bank] ) |
precharge_flag[kill_bank] <= #(`tRP-1) `FALSE; |
end |
end |
always @(rd_precharge_flag_kill) begin |
if (prech_reg[0] == `TRUE) begin |
for (i = 0; i < `nBank; i = i+1) |
precharge_flag[i] <= #(`tRP-1) `FALSE; |
end |
else begin |
if( precharge_flag[rd_kill_bank] ) |
precharge_flag[rd_kill_bank] <= #(`tRP-1) `FALSE; |
end |
end |
always @(wr_precharge_flag_kill) begin |
if (prech_reg[0] == `TRUE) begin |
for (i = 0; i < `nBank; i = i+1) |
precharge_flag[i] <= #(`tRP-1) `FALSE; |
end |
else begin |
if( precharge_flag[wr_kill_bank] ) |
precharge_flag[wr_kill_bank] <= #(`tRP-1) `FALSE; |
end |
end |
`endprotect |
|
/* |
*----------------------------------------------------- |
* read task |
*----------------------------------------------------- |
*/ |
|
task read_task; |
|
begin |
|
begin: read_op |
integer i; |
|
for( i=0; i < BL; i=i+1 ) |
begin |
t_dqo = dout_reg[i]; |
->dqo_event; |
@(posedge pclk); |
`ifdef M16G4_M64G3 // jhkim(8.14) |
if( i == `PAGEDEPTH - 1 ) |
i = -1; // full page wrap around |
`endif |
end |
end |
|
end |
endtask |
|
/* |
*----------------------------------------------------- |
* write task |
*----------------------------------------------------- |
*/ |
|
task write_task; |
begin |
begin: write_op |
integer i, j, k; |
reg [`BIT] tmp_reg; |
integer bank_id; |
reg [8*8:1] str; |
|
if(~burst_type) |
increment_read; |
else |
interleave_read; |
|
begin: write_seq |
for(i = 0; i < WBL; i = i+1) |
begin // { for loop |
begin |
bank_id = BankSelect(c_bank_addr); |
str = PrintBank(c_bank_addr); |
if(precharge_flag[bank_id] == `TRUE) |
disable write_seq; |
case (bank_id) |
'd0: tmp_reg = din_rega[i]; |
'd1: tmp_reg = din_regb[i]; |
`ifdef NBANK4 |
'd2: tmp_reg = din_regc[i]; |
'd3: tmp_reg = din_regd[i]; |
`endif |
endcase |
|
|
for (k = 0; k < `nDQM; k = k + 1) begin |
if (dqm[k] == 1'b0) begin |
for (j = k*`BYTE; j < (k+1)*`BYTE; j = j + 1) begin |
tmp_reg[j] = (dqi[j] == 1'b1 || dqi[j] == 1'b0)? |
dqi[j]:1'bx; |
end |
end |
end |
|
case (bank_id) |
'd0: din_rega[i] = tmp_reg; |
'd1: din_regb[i] = tmp_reg; |
`ifdef NBANK4 |
'd2: din_regc[i] = tmp_reg; |
'd3: din_regd[i] = tmp_reg; |
`endif |
endcase |
end |
|
m_addr = {r_addr, c_addr}; |
#0 ->flush_write; |
|
`ifdef M16G4_M64G3 // jhkim(8.14) |
if( i == WBL-1 && WBL !== `PAGEDEPTH ) |
disable write_seq; |
`else |
if( i == WBL-1 && i != `PAGEDEPTH ) |
disable write_seq; |
`endif |
@(posedge pclk); |
#0.1; //KyW ... 0408 for VCS |
if( |dqm === 1'b0 ) begin // 98.6.26 BYC |
if( CUR_TIME - TDQI < `tSS-`MARGIN ) |
$display("Warning: DQi setup violation at %t", CUR_TIME); |
end |
`ifdef M16G4_M64G3 // jhkim(8.14) |
if ( i == `PAGEDEPTH -1) |
i = -1; // full page wrap around |
`endif |
|
end // } for loop end |
end // write_seq |
|
// m_addr = {r_addr, c_addr}; |
// ->flush_write; |
|
end |
|
end |
|
endtask |
|
`ifdef NBANK2 |
function integer BankSelect; |
input c_addr; |
integer bank; |
begin |
case(c_addr) |
1'b0 : |
bank = 0; |
1'b1 : |
bank = 1; |
default : |
bank = -1; |
endcase |
BankSelect = bank; |
end |
endfunction |
function [8*8 : 1] PrintBank; |
input bs; |
reg [8*8 : 1] s_bank; |
begin |
case(bs) |
1'b0 : |
s_bank = " A Bank"; |
1'b1 : |
s_bank = " B Bank"; |
default : |
s_bank = "Bad Bank"; |
endcase |
PrintBank = s_bank; |
end |
endfunction |
`endif |
|
`ifdef NBANK4 |
function integer BankSelect; |
input [1:0] c_addr; |
integer bank; |
begin |
case(c_addr) |
2'b00 : |
bank = 0; |
2'b01 : |
bank = 1; |
2'b10 : |
bank = 2; |
2'b11 : |
bank = 3; |
default : |
bank = -1; |
endcase |
BankSelect = bank; |
end |
endfunction |
function [8*8 : 1] PrintBank; |
input [1:0] bs; |
reg [8*8 : 1] s_bank; |
begin |
case(bs) |
2'b00 : |
s_bank = " A Bank"; |
2'b01 : |
s_bank = " B Bank"; |
2'b10 : |
s_bank = " C Bank"; |
2'b11 : |
s_bank = " D Bank"; |
default : |
s_bank = "Bad Bank"; |
endcase |
PrintBank = s_bank; |
end |
endfunction |
`endif |
|
endmodule |
|
`ifdef CS2 |
`ifdef DPD_PIN |
module sdram(clk, cs0b, cs1b, cke, ba, ad, rasb, casb, web, dqm, dqi, dpdb); |
`else |
module sdram(clk, cs0b, cs1b, cke, ba, ad, rasb, casb, web, dqm, dqi); |
`endif |
|
inout [`BIT] dqi; |
input [`nBank/2-1:0] ba; |
input [`ADDRTOP:0] ad; |
input rasb,casb,web; |
input clk,cke,cs0b,cs1b; |
input [`nDQM-1:0] dqm; |
|
`ifdef DPD_PIN |
input dpdb; |
`endif |
|
`ifdef DPD_PIN |
sdram_cs2 i0(clk, cs0b, cke, ba, ad, rasb, casb, web, dqm, dqi, dpdb); |
sdram_cs2 i1(clk, cs1b, cke, ba, ad, rasb, casb, web, dqm, dqi, dpdb); |
`else |
sdram_cs2 i0(clk, cs0b, cke, ba, ad, rasb, casb, web, dqm, dqi); |
sdram_cs2 i1(clk, cs1b, cke, ba, ad, rasb, casb, web, dqm, dqi); |
`endif |
endmodule |
`endif |
|
`ifdef CS2_CKE2 |
`ifdef DPD_PIN |
module sdram(clk, cs0b, cs1b, cke0, cke1, ba, ad, rasb, casb, web, dqm, dqi, dpdb); |
`else |
module sdram(clk, cs0b, cs1b, cke0, cke1, ba, ad, rasb, casb, web, dqm, dqi); |
`endif |
|
inout [`BIT] dqi; |
input [`nBank/2-1:0] ba; |
input [`ADDRTOP:0] ad; |
input rasb,casb,web; |
input clk,cke0,cke1,cs0b,cs1b; |
input [`nDQM-1:0] dqm; |
|
`ifdef DPD_PIN |
input dpdb; |
`endif |
|
`ifdef DPD_PIN |
sdram_cs2 i0(clk, cs0b, cke0, ba, ad, rasb, casb, web, dqm, dqi, dpdb); |
sdram_cs2 i1(clk, cs1b, cke1, ba, ad, rasb, casb, web, dqm, dqi, dpdb); |
`else |
sdram_cs2 i0(clk, cs0b, cke0, ba, ad, rasb, casb, web, dqm, dqi); |
sdram_cs2 i1(clk, cs1b, cke1, ba, ad, rasb, casb, web, dqm, dqi); |
`endif |
endmodule |
`endif |
|
/ramctrl/ramctrl.v
0,0 → 1,563
// |
// ramctrl.v -- RAM controller |
// |
|
|
`include "ramctrl/k4s561632e.v" |
|
|
`timescale 1ns/10ps |
`default_nettype none |
|
|
`define MODE 13'h0032 // CL = 3, sequ. burst length = 4 |
|
`define CMD_MRSET 3'b000 // mode register set |
`define CMD_ARFRS 3'b001 // auto refresh |
`define CMD_PRCHG 3'b010 // precharge (deactivate row/rows) |
`define CMD_ACTV 3'b011 // select bank, activate row |
`define CMD_WRITE 3'b100 // select bank & column, start write |
`define CMD_READ 3'b101 // select bank & column, start read |
`define CMD_BSTOP 3'b110 // burst stop |
`define CMD_NOP 3'b111 // no operation |
|
// |
// Note: The FSM is a registered Mealy machine. Its actions, which |
// are noted here for a specific state, take place in the next |
// clock cycle. This is only a notational problem: the actions |
// should in fact be associated with state transitions. |
// |
// ST_RESET // NOP, CKE=0, CS_N=1, wait 100 us |
`define ST_INIT0 5'd0 // NOP, CKE=1, CS_N=0, wait 100 us |
`define ST_INIT1 5'd1 // PRECHARGE ALL |
`define ST_INIT2 5'd2 // NOP, wait tRP - 1 cycle |
`define ST_INIT3 5'd3 // AUTO REFRESH |
`define ST_INIT4 5'd4 // NOP, wait tRFC - 1 cycle |
`define ST_INIT5 5'd5 // AUTO REFRESH |
`define ST_INIT6 5'd6 // NOP, wait tRFC - 1 cycle |
`define ST_INIT7 5'd7 // MODE REGISTER SET |
`define ST_INIT8 5'd8 // NOP, wait tMRD - 1 cycle |
`define ST_IDLE 5'd9 // AUTO REFRESH, ACTIVE, or NOP |
`define ST_RFRSH 5'd10 // NOP, wait tRFC - 1 cycle |
`define ST_WRDATA0 5'd11 // NOP, wait tRCD - 1 cycle |
`define ST_WRDATA1 5'd12 // WRITE, de=1 |
`define ST_WRDATA2 5'd13 // NOP, wait 3 cycles |
`define ST_WRDATA3 5'd14 // NOP, ack=1, de=0, wait 2 cycles |
`define ST_WRDATA4 5'd15 // NOP, ack=0, wait 2 cycles |
`define ST_RDDATA0 5'd16 // NOP, wait tRCD - 1 cycle |
`define ST_RDDATA1 5'd17 // READ |
`define ST_RDDATA2 5'd18 // NOP, wait 2 cycles |
`define ST_RDDATA3 5'd19 // NOP, ld=1, wait 4 cycles |
`define ST_RDDATA4 5'd20 // NOP, ack=1, ld=0, wait 2 cycles |
`define ST_RDDATA5 5'd21 // NOP, ack=0, wait 3 cycles |
`define ST_RDINST0 5'd22 // NOP, wait tRCD - 1 cycle |
`define ST_RDINST1 5'd23 // READ |
`define ST_RDINST2 5'd24 // NOP, wait 2 cycles |
`define ST_RDINST3 5'd25 // NOP, ld=1, wait 4 cycles |
`define ST_RDINST4 5'd26 // NOP, ack=1, ld=0, wait 2 cycles |
`define ST_RDINST5 5'd27 // NOP, ack=0, wait 3 cycles |
`define ST_ILLDA0 5'd28 // NOP, data_timeout=1, wait 2 cycles |
`define ST_ILLDA1 5'd29 // NOP, data_timeout=0 |
`define ST_ILLIA0 5'd30 // NOP, inst_timeout=1, wait 2 cycles |
`define ST_ILLIA1 5'd31 // NOP, inst_timeout=0 |
|
`define T_INIT0 14'd10000 // min 100 usec with CKE = 0 |
`define T_INIT1 14'd10000 // min 100 usec with CKE = 1 |
`define T_RP 14'd3 // min 20 ns row precharge time |
`define T_RFC 14'd9 // min 66 ns auto refresh period |
`define T_MRD 14'd3 // min load mode register delay |
`define T_RCD 14'd3 // min 20 ns active-to-rw delay |
|
`define REFCNT 10'd780 // 8192 refresh cycles per 64 ms |
|
|
module ramctrl(clk_ok, clk, |
inst_stb, inst_addr, |
inst_dout, inst_ack, |
inst_timeout, |
data_stb, data_we, |
data_addr, data_din, |
data_dout, data_ack, |
data_timeout); |
input clk_ok; |
input clk; |
input inst_stb; |
input [25:0] inst_addr; |
output [63:0] inst_dout; |
output reg inst_ack; |
output reg inst_timeout; |
input data_stb; |
input data_we; |
input [25:0] data_addr; |
input [63:0] data_din; |
output [63:0] data_dout; |
output reg data_ack; |
output reg data_timeout; |
|
wire sdram_clk; |
wire sdram_clk_aux; |
reg sdram_cke; |
reg sdram_cs_n; |
wire sdram_ras_n; |
wire sdram_cas_n; |
wire sdram_we_n; |
reg [1:0] sdram_ba; |
reg [12:0] sdram_a; |
wire [1:0] sdram_dqm; |
wire [15:0] sdram_dq; |
|
reg [1:0] ram_cnt; |
wire [15:0] ram_dout; |
reg ram_de; |
reg [63:0] data; |
reg data_ld; |
|
wire inst_addr_out_of_range; |
wire data_addr_out_of_range; |
|
reg [2:0] ram_cmd; |
reg [1:0] ram_dqm; |
reg [13:0] count; |
reg [4:0] state; |
|
reg [9:0] refcnt; |
reg refflg; |
reg refrst; |
|
// |
// create ram instance |
// |
|
sdram sdram_1( |
.clk(sdram_clk), |
.cke(sdram_cke), |
.csb(sdram_cs_n), |
.rasb(sdram_ras_n), |
.casb(sdram_cas_n), |
.web(sdram_we_n), |
.ba(sdram_ba[1:0]), |
.ad(sdram_a[12:0]), |
.dqm(sdram_dqm[1:0]), |
.dqi(sdram_dq[15:0]) |
); |
|
// |
// clock output to ram |
// the necessary phase shift will be accomplished by |
// a DLL if the controller is implemented on an FPGA |
// |
|
not #4 not_1(sdram_clk_aux, clk); |
not #5 not_2(sdram_clk, sdram_clk_aux); |
|
// |
// data output to ram |
// |
|
assign ram_dout[15:0] = |
~ram_cnt[1] ? (~ram_cnt[0] ? data_din[63:48] : data_din[47:32]) : |
(~ram_cnt[0] ? data_din[31:16] : data_din[15: 0]); |
assign sdram_dq[15:0] = ram_de ? ram_dout[15:0] : 16'hzzzz; |
|
// |
// data output to cache |
// |
|
always @(posedge clk) begin |
if (data_ld & (ram_cnt[1:0] == 2'b00)) begin |
data[63:48] <= sdram_dq[15:0]; |
end |
if (data_ld & (ram_cnt[1:0] == 2'b01)) begin |
data[47:32] <= sdram_dq[15:0]; |
end |
if (data_ld & (ram_cnt[1:0] == 2'b10)) begin |
data[31:16] <= sdram_dq[15:0]; |
end |
if (data_ld & (ram_cnt[1:0] == 2'b11)) begin |
data[15: 0] <= sdram_dq[15:0]; |
end |
end |
|
assign inst_dout[63:0] = data[63:0]; |
assign data_dout[63:0] = data[63:0]; |
|
// |
// address range check |
// |
|
assign inst_addr_out_of_range = | inst_addr[25:22]; |
assign data_addr_out_of_range = | data_addr[25:22]; |
|
// |
// ramctrl state machine |
// |
|
assign sdram_ras_n = ram_cmd[2]; |
assign sdram_cas_n = ram_cmd[1]; |
assign sdram_we_n = ram_cmd[0]; |
|
assign sdram_dqm[1] = ram_dqm[1]; |
assign sdram_dqm[0] = ram_dqm[0]; |
|
always @(posedge clk or negedge clk_ok) begin |
// asynchronous reset |
if (~clk_ok) begin |
inst_ack <= 0; |
inst_timeout <= 0; |
data_ack <= 0; |
data_timeout <= 0; |
sdram_cke <= 0; |
sdram_cs_n <= 1; |
ram_cnt <= 0; |
ram_de <= 0; |
data_ld <= 0; |
ram_cmd <= `CMD_NOP; |
ram_dqm <= 2'b11; |
count <= `T_INIT0 - 1; |
state <= `ST_INIT0; |
refrst <= 0; |
end else begin |
if (|count[13:0]) begin |
// wait until count = 0 |
// if count is loaded with N on a state transition, the |
// new state will last for (N+1)/fclk cycles before (!) |
// any action specified in the new state will take place |
count <= count - 1; |
// ram_cnt cycles through the 16-bit half-words in SDRAM |
// during burst read/writes while the main state machine |
// waits, thus it must be incremented here |
ram_cnt <= ram_cnt + 1; |
end else begin |
case (state) |
//---------------------------- |
// init |
//---------------------------- |
`ST_INIT0: |
begin |
sdram_cke <= 1; |
sdram_cs_n <= 0; |
ram_cmd <= `CMD_NOP; |
count <= `T_INIT1 - 1; |
state <= `ST_INIT1; |
end |
`ST_INIT1: |
begin |
ram_cmd <= `CMD_PRCHG; |
sdram_ba <= 2'b00; // don't care |
sdram_a <= 13'h0400; // precharge all |
state <= `ST_INIT2; |
end |
`ST_INIT2: |
begin |
ram_cmd <= `CMD_NOP; |
count <= `T_RP - 2; |
state <= `ST_INIT3; |
end |
`ST_INIT3: |
begin |
ram_cmd <= `CMD_ARFRS; |
state <= `ST_INIT4; |
end |
`ST_INIT4: |
begin |
ram_cmd <= `CMD_NOP; |
count <= `T_RFC - 2; |
state <= `ST_INIT5; |
end |
`ST_INIT5: |
begin |
ram_cmd <= `CMD_ARFRS; |
state <= `ST_INIT6; |
end |
`ST_INIT6: |
begin |
ram_cmd <= `CMD_NOP; |
count <= `T_RFC - 2; |
state <= `ST_INIT7; |
end |
`ST_INIT7: |
begin |
ram_cmd <= `CMD_MRSET; |
sdram_ba <= 2'b00; |
sdram_a <= `MODE; |
state <= `ST_INIT8; |
end |
`ST_INIT8: |
begin |
ram_cmd <= `CMD_NOP; |
ram_dqm <= 2'b00; |
count <= `T_MRD - 2; |
state <= `ST_IDLE; |
end |
//---------------------------- |
// idle |
//---------------------------- |
`ST_IDLE: |
begin |
if (refflg) begin |
// refresh request |
ram_cmd <= `CMD_ARFRS; |
state <= `ST_RFRSH; |
refrst <= 1; |
end else begin |
if (data_stb) begin |
if (data_addr_out_of_range) begin |
// illegal data address |
ram_cmd <= `CMD_NOP; |
state <= `ST_ILLDA0; |
end else begin |
// data address is ok |
if (data_we) begin |
// data write request |
ram_cmd <= `CMD_ACTV; |
sdram_ba <= data_addr[21:20]; |
sdram_a <= data_addr[19:7]; |
state <= `ST_WRDATA0; |
end else begin |
// data read request |
ram_cmd <= `CMD_ACTV; |
sdram_ba <= data_addr[21:20]; |
sdram_a <= data_addr[19:7]; |
state <= `ST_RDDATA0; |
end |
end |
end else begin |
if (inst_stb) begin |
if (inst_addr_out_of_range) begin |
// illegal inst address |
ram_cmd <= `CMD_NOP; |
state <= `ST_ILLIA0; |
end else begin |
// inst address is ok |
// inst read request |
ram_cmd <= `CMD_ACTV; |
sdram_ba <= inst_addr[21:20]; |
sdram_a <= inst_addr[19:7]; |
state <= `ST_RDINST0; |
end |
end else begin |
// no request |
ram_cmd <= `CMD_NOP; |
state <= `ST_IDLE; |
end |
end |
end |
end |
//---------------------------- |
// refresh |
//---------------------------- |
`ST_RFRSH: |
begin |
ram_cmd <= `CMD_NOP; |
count <= `T_RFC - 2; |
state <= `ST_IDLE; |
refrst <= 0; |
end |
//---------------------------- |
// write data |
//---------------------------- |
`ST_WRDATA0: |
begin |
ram_cmd <= `CMD_NOP; |
count <= `T_RCD - 2; |
state <= `ST_WRDATA1; |
end |
`ST_WRDATA1: |
begin |
ram_cnt <= 0; |
ram_de <= 1; |
ram_cmd <= `CMD_WRITE; |
sdram_ba <= data_addr[21:20]; |
sdram_a <= { 6'b0010, data_addr[6:0], 2'b00 }; |
state <= `ST_WRDATA2; |
end |
`ST_WRDATA2: |
begin |
ram_cnt <= ram_cnt + 1; |
ram_cmd <= `CMD_NOP; |
count <= 2; |
state <= `ST_WRDATA3; |
end |
`ST_WRDATA3: |
begin |
data_ack <= 1; |
ram_de <= 0; |
ram_cmd <= `CMD_NOP; |
count <= 1; |
state <= `ST_WRDATA4; |
end |
`ST_WRDATA4: |
begin |
data_ack <= 0; |
ram_cmd <= `CMD_NOP; |
count <= 1; |
state <= `ST_IDLE; |
end |
//---------------------------- |
// read data |
//---------------------------- |
`ST_RDDATA0: |
begin |
ram_cmd <= `CMD_NOP; |
count <= `T_RCD - 2; |
state <= `ST_RDDATA1; |
end |
`ST_RDDATA1: |
begin |
ram_cmd <= `CMD_READ; |
sdram_ba <= data_addr[21:20]; |
sdram_a <= { 6'b0010, data_addr[6:0], 2'b00 }; |
state <= `ST_RDDATA2; |
end |
`ST_RDDATA2: |
begin |
ram_cmd <= `CMD_NOP; |
count <= 1; |
state <= `ST_RDDATA3; |
end |
`ST_RDDATA3: |
begin |
ram_cnt <= 0; |
data_ld <= 1; |
ram_cmd <= `CMD_NOP; |
count <= 3; |
state <= `ST_RDDATA4; |
end |
`ST_RDDATA4: |
begin |
data_ack <= 1; |
data_ld <= 0; |
ram_cmd <= `CMD_NOP; |
count <= 1; |
state <= `ST_RDDATA5; |
end |
`ST_RDDATA5: |
begin |
data_ack <= 0; |
ram_cmd <= `CMD_NOP; |
count <= 2; |
state <= `ST_IDLE; |
end |
//---------------------------- |
// read inst |
//---------------------------- |
`ST_RDINST0: |
begin |
ram_cmd <= `CMD_NOP; |
count <= `T_RCD - 2; |
state <= `ST_RDINST1; |
end |
`ST_RDINST1: |
begin |
ram_cmd <= `CMD_READ; |
sdram_ba <= inst_addr[21:20]; |
sdram_a <= { 6'b0010, inst_addr[6:0], 2'b00 }; |
state <= `ST_RDINST2; |
end |
`ST_RDINST2: |
begin |
ram_cmd <= `CMD_NOP; |
count <= 1; |
state <= `ST_RDINST3; |
end |
`ST_RDINST3: |
begin |
ram_cnt <= 0; |
data_ld <= 1; |
ram_cmd <= `CMD_NOP; |
count <= 3; |
state <= `ST_RDINST4; |
end |
`ST_RDINST4: |
begin |
inst_ack <= 1; |
data_ld <= 0; |
ram_cmd <= `CMD_NOP; |
count <= 1; |
state <= `ST_RDINST5; |
end |
`ST_RDINST5: |
begin |
inst_ack <= 0; |
ram_cmd <= `CMD_NOP; |
count <= 2; |
state <= `ST_IDLE; |
end |
//---------------------------- |
// illegal data address |
//---------------------------- |
`ST_ILLDA0: |
begin |
data_timeout <= 1; |
ram_cmd <= `CMD_NOP; |
count <= 1; |
state <= `ST_ILLDA1; |
end |
`ST_ILLDA1: |
begin |
data_timeout <= 0; |
ram_cmd <= `CMD_NOP; |
state <= `ST_IDLE; |
end |
//---------------------------- |
// illegal inst address |
//---------------------------- |
`ST_ILLIA0: |
begin |
inst_timeout <= 1; |
ram_cmd <= `CMD_NOP; |
count <= 1; |
state <= `ST_ILLIA1; |
end |
`ST_ILLIA1: |
begin |
inst_timeout <= 0; |
ram_cmd <= `CMD_NOP; |
state <= `ST_IDLE; |
end |
//---------------------------- |
// not used |
//---------------------------- |
default: |
begin |
inst_ack <= 0; |
inst_timeout <= 0; |
data_ack <= 0; |
data_timeout <= 0; |
sdram_cke <= 0; |
sdram_cs_n <= 1; |
ram_cnt <= 0; |
ram_de <= 0; |
data_ld <= 0; |
ram_cmd <= `CMD_NOP; |
ram_dqm <= 2'b11; |
count <= `T_INIT0 - 1; |
state <= `ST_INIT0; |
refrst <= 0; |
end |
endcase |
end |
end |
end |
|
// |
// refresh counter |
// |
|
always @(posedge clk or negedge clk_ok) begin |
if (~clk_ok) begin |
refcnt <= 10'd0; |
end else begin |
if (refcnt == 10'd0) begin |
refcnt <= `REFCNT; |
refflg <= 1; |
end else begin |
refcnt <= refcnt - 1; |
if (refrst) begin |
refflg <= 0; |
end |
end |
end |
end |
|
endmodule |
/memtest.cfg
0,0 → 1,74
[timestart] 0 |
[size] 1280 725 |
[pos] -1 -1 |
*-16.000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 |
[treeopen] memtest. |
[treeopen] memtest.ramctrl_1. |
@28 |
memtest.clk2 |
memtest.clk |
memtest.clk_ok |
memtest.rst |
@200 |
--- INST RD -- |
@28 |
memtest.inst_stb |
@22 |
memtest.inst_addr[25:0] |
memtest.inst_to_cache[63:0] |
@28 |
memtest.inst_ack |
memtest.inst_timeout |
@200 |
--- DATA RD/WR -- |
@28 |
memtest.data_stb |
memtest.data_we |
@22 |
memtest.data_addr[25:0] |
memtest.data_to_mctrl[63:0] |
memtest.data_to_cache[63:0] |
@28 |
memtest.data_ack |
memtest.data_timeout |
@200 |
--- TEST RESULT -- |
@28 |
memtest.test_ended |
memtest.test_error |
@200 |
--- SDRAM CHIP -- |
@28 |
memtest.ramctrl_1.sdram_clk |
memtest.ramctrl_1.sdram_cke |
memtest.ramctrl_1.sdram_cs_n |
memtest.ramctrl_1.sdram_ras_n |
memtest.ramctrl_1.sdram_cas_n |
memtest.ramctrl_1.sdram_we_n |
memtest.ramctrl_1.sdram_ba[1:0] |
@22 |
memtest.ramctrl_1.sdram_a[12:0] |
@28 |
memtest.ramctrl_1.sdram_dqm[1:0] |
@22 |
memtest.ramctrl_1.sdram_dq[15:0] |
@200 |
--- SDRAM CTRL -- |
@28 |
memtest.ramctrl_1.ram_cnt[1:0] |
@22 |
memtest.ramctrl_1.ram_dout[15:0] |
@28 |
memtest.ramctrl_1.ram_de |
@22 |
memtest.ramctrl_1.data[63:0] |
@28 |
memtest.ramctrl_1.data_ld |
memtest.ramctrl_1.ram_cmd[2:0] |
@22 |
memtest.ramctrl_1.count[13:0] |
memtest.ramctrl_1.state[4:0] |
memtest.ramctrl_1.refcnt[9:0] |
@28 |
memtest.ramctrl_1.refflg |
memtest.ramctrl_1.refrst |
/Makefile
0,0 → 1,18
# |
# Makefile for testing the memory controller |
# |
|
all: show |
|
install: |
|
memtest: memtest.v |
iverilog -Wall -o memtest memtest.v |
|
show: memtest |
./memtest |
gtkwave dump.vcd memtest.cfg |
|
clean: |
rm -f *~ memtest dump.vcd |
rm -f ramtest/*~ ramctrl/*~ |
/README
0,0 → 1,49
Structure |
--------- |
|
A top-level module (memtest.v) creates instances of a memory |
test circuit (ramtest/ramtest.v) and a memory controller |
(ramctrl/ramctrl.v), which in turn builds an internal model |
of the external SDRAM (ramctrl/k4s561632e.v). |
|
|
Intended Use |
------------ |
|
The memory controller offers a complete simulation of the memory |
subsystem, including a simulation model of a 256 Mbit SDRAM chip |
(provided by Samsung Electronics). The controller can also be |
synthesized for use on a real FPGA (but the DLL for clock phase |
shifting required in this case is not included here). |
|
|
Front-End (interface to caches) |
------------------------------- |
|
instruction read: |
2^26 * 64 bit = 512 MB |
strobe/acknowledge/timeout handshake |
|
data read/write: |
2^26 * 64 bit = 512 MB |
strobe/acknowledge/timeout handshake |
|
|
Back-End (interface to SDRAM) |
----------------------------- |
|
This is the standard SDRAM interface for 256 Mbit devices, |
organized as 16 M x 16 bit (in 4 banks, 8192 rows each). |
4 banks * 8192 rows * 512 columns * 16 bit = 256 Mbit = 32 MB |
|
|
Clocks |
------ |
|
The SDRAM controller (and the SDRAM itself) is clocked with |
100 MHz, the rest of the circuit is clocked with 50 MHz. The |
clocks are synchronized, so that every other positive clock |
edge at 100 MHz coincides with a positive clock edge at 50 MHz. |
Therefore we don't need complicated circuits (FIFO, etc.) to |
safely cross the clock domain border; simply stretching both |
acknowledge signals to two 100 MHz clock cycles will do. |