📄 odt_watchdog.v
字号:
// ===========================================================================
// Verilog module generated by IPexpress
// Filename: odt_watchdog.v
// Copyright 2006 (c) Lattice Semiconductor Corporation. All rights reserved.
// ===========================================================================
`timescale 1 ps / 1 ps
module odt_watchdog(
mem_clk,
rst_n,
//------- Signals from SDRAM side
ddr_cke, // DDR SDRAM Clock enable
ddr_cs_n, // DDR SDRAM Chip select
ddr_we_n, // DDR SDRAM Write enable
ddr_cas_n, // DDR SDRAM Column address strobe
ddr_ras_n, // DDR SDRAM Row address strobe
ddr_ad, // DDR SDRAM Address bus
ddr_ba, // DDR SDRAM Bank bus
ddr_dqm, // DDR SDRAM Data Mask signal
ddr_dq, // DDR SDRAM Data Bus
ddr_dqs, // DDR SDRAM Data Strobe
ddr_odt // DDR SDRAM ODT signal
);
input mem_clk;
input rst_n;
input ddr_cke;
input [`CS_WIDTH-1:0] ddr_cs_n;
input ddr_we_n;
input ddr_cas_n;
input ddr_ras_n;
input [`ROW_WIDTH-1:0] ddr_ad;
input [`BNK_WDTH-1:0] ddr_ba;
input [`DSIZE/2-1:0] ddr_dq;
input [`DSIZE/16-1:0] ddr_dqm;
input [`DSIZE/16-1:0] ddr_dqs;
input [`CS_WIDTH-1:0] ddr_odt;
///////////////////////////////////////////////////////////////////////
// delay the DQS signal so that the edge is sepearted from the clock.
wire [`DSIZE/16-1:0] ddr_dqs_dly;
assign #1 ddr_dqs_dly = ddr_dqs;
///////////////////////////////////////////////////////////////////////
// Shadow registers in the test bench
reg [2:0] burst_len;
reg [2:0] cas_lat;
reg [2:0] add_lat;
///////////////////////////////////////////////////////////////////////
// flopped signals
reg mem_pd_cmd_d;
reg mem_sref_cmd_d;
reg mem_rd_cmd_d;
reg mem_wr_cmd_d;
reg mem_lmr_cmd_d;
reg [1:0] ddr_cs_n_d[0:7];
reg [1:0] wr_ddr_cs_n_d[0:7];
reg [1:0] ddr_ba_d;
// signals that indicate the type of command at the memory interface
wire mem_sref_cmd;
wire mem_pd_cmd;
wire mem_lmr_cmd;
wire mem_aref_cmd;
wire mem_act_cmd;
wire mem_pre_cmd;
wire mem_rd_cmd;
wire mem_wr_cmd;
wire mem_nop_cmd;
wire [2:0] read_lat;
wire [2:0] write_lat;
wire [1:0] chipsel; // chip select signals to the memory
reg [2:0] cmd_cnt_ptr; // cmd_fifo write pointer
reg [3:0] cmd_counter[0:7];
reg [7:0] cmd_count_en;
reg [2:0] wr_cmd_cnt_ptr; // cmd_fifo write pointer
reg [3:0] wr_cmd_counter[0:7];
reg [7:0] wr_cmd_count_en;
///////////////////////////////////////////////////////////////////////
// Debug logic
wire [3:0] debug_cmd_counter_0;
wire [3:0] debug_cmd_counter_1;
wire [3:0] debug_cmd_counter_2;
wire [3:0] debug_cmd_counter_3;
wire [3:0] debug_cmd_counter_4;
wire [3:0] debug_cmd_counter_5;
wire [3:0] debug_cmd_counter_6;
wire [3:0] debug_cmd_counter_7;
assign debug_cmd_counter_0 = cmd_counter[0];
assign debug_cmd_counter_1 = cmd_counter[1];
assign debug_cmd_counter_2 = cmd_counter[2];
assign debug_cmd_counter_3 = cmd_counter[3];
assign debug_cmd_counter_4 = cmd_counter[4];
assign debug_cmd_counter_5 = cmd_counter[5];
assign debug_cmd_counter_6 = cmd_counter[6];
assign debug_cmd_counter_7 = cmd_counter[7];
///////////////////////////////////////////////////////////////////////
// This part of the logic tracks the LMR command on the memory
// interface and updates the shadow mode registers.
reg [3:0] int_burst_len;
initial begin
cmd_count_en = 8'b0;
wr_cmd_count_en = 8'b0;
end
always @ (posedge mem_clk or negedge rst_n) begin
if (!rst_n) begin
burst_len <= 3'b010;
cas_lat <= 3'b011;
add_lat <= 3'b011;
end
else if (mem_lmr_cmd && (ddr_ba[1:0] == 2'b00)) begin
burst_len <= ddr_ad[2:0];
cas_lat <= ddr_ad[6:4];
end
else if (mem_lmr_cmd && (ddr_ba[1:0] == 2'b01)) begin
add_lat <= ddr_ad[5:3];
end
end
assign read_lat = cas_lat + add_lat;
assign write_lat = read_lat - 1;
always @ (burst_len) begin
case (burst_len)
3'b001 : int_burst_len = 4'b0010;
3'b010 : int_burst_len = 4'b0100;
3'b011 : int_burst_len = 4'b1000;
default : int_burst_len = 4'b0100;
endcase
end
///////////////////////////////////////////////////////////////////////
// This logic detects the command presented at the memory interface.
// self refresh: cke=0, cs=0, ras=0, cas=0, we=1
// powerdown: cke=0
// lmr: cs=0, ras=0, cas=0, we=0
// act: cs=0, ras=0, cas=1, we=1
// pre: cs=0, ras=0, cas=1, we=0
// nop: cs=0, ras=1, cas=1, we=1
// Read: cs=0, ras=1, cas=0, we=1
// Write: cs=0, ras=1, cas=0, we=0
assign mem_rd_cmd = ~(&ddr_cs_n) & ddr_ras_n & ~ddr_cas_n & ddr_we_n;
assign mem_wr_cmd = ~(&ddr_cs_n) & ddr_ras_n & ~ddr_cas_n & ~ddr_we_n;
assign mem_sref_cmd = ~(&ddr_cs_n) & ~ddr_cke &
~ddr_ras_n & ~ddr_cas_n & ddr_we_n;
assign mem_pd_cmd = ~(&ddr_cs_n) & ddr_ras_n & ddr_cas_n & ddr_we_n & ~ddr_cke;
assign mem_lmr_cmd = ~(&ddr_cs_n) & ~ddr_ras_n & ~ddr_cas_n & ~ddr_we_n;
assign mem_act_cmd = ~(&ddr_cs_n) & ~ddr_ras_n & ddr_cas_n & ddr_we_n;
assign mem_pre_cmd = ~(&ddr_cs_n) & ~ddr_ras_n & ddr_cas_n & ~ddr_we_n;
assign mem_nop_cmd = (~(&ddr_cs_n) & ddr_ras_n & ddr_cas_n & ddr_we_n) |
&ddr_cs_n;
///////////////////////////////////////////////////////////////////////
// This logic stores the read, write commands seen at the
// memory interface in cmd_fifo.
`ifdef CS_WIDTH_1
assign chipsel = 2'b00; // both are set to 0 for just one chip sel
`else
assign chipsel = ddr_cs_n;
`endif
always @ (posedge mem_clk or negedge rst_n) begin
if (!rst_n) begin
cmd_cnt_ptr <= 8'b0;
wr_cmd_cnt_ptr <= 3'b0;
end
else begin
if (mem_rd_cmd) begin
cmd_cnt_ptr <= cmd_cnt_ptr + 1;
end
if (mem_wr_cmd) begin
wr_cmd_cnt_ptr <= wr_cmd_cnt_ptr + 1;
end
end
end
///////////////////////////////////////////////////////////////////////
// Edge that samples command is edge 0. All clock edges are then
// counted in the increasing order.
// Check if the ODT signal for both chip selects are asserted
`ifdef CS_WIDTH_1
`else
always @ (posedge mem_clk) begin
if (^ddr_odt == 1'b0 && |ddr_odt == 1'b1) begin
$display ("ODT ERROR: two ODT signals asserted at time %0t\n",$time);
end
end
`endif
///////////////////////////////////////////////////////////////////////
// The monitor accepts upto eight commands in a queue. The commands
// are numbered based on the cmd_cnt_ptr value. Each command has it's
// own edge counter to determine the edges where the ODT signal should be
// sampled asserted. These counters kick in from the moment a command is
// presented to the queue. Since the read command with CL=4, AL=4 and
// BL=8 requires a count of upto 9, the counters are 4 bit long and will
// be reset when they reach the max count possible for the configuration.
integer i;
always @ (posedge mem_clk) begin
if (mem_rd_cmd) begin
case (cmd_cnt_ptr)
3'd0: begin
cmd_count_en[0] <= 1;
cmd_counter[0] <= 1;
ddr_cs_n_d[0] <= ddr_cs_n;
end
3'd1: begin
cmd_count_en[1] <= 1;
cmd_counter[1] <= 1;
ddr_cs_n_d[1] <= ddr_cs_n;
end
3'd2: begin
cmd_count_en[2] <= 1;
cmd_counter[2] <= 1;
ddr_cs_n_d[2] <= ddr_cs_n;
end
3'd3: begin
cmd_count_en[3] <= 1;
cmd_counter[3] <= 1;
ddr_cs_n_d[3] <= ddr_cs_n;
end
3'd4: begin
cmd_count_en[4] <= 1;
cmd_counter[4] <= 1;
ddr_cs_n_d[4] <= ddr_cs_n;
end
3'd5: begin
cmd_count_en[5] <= 1;
cmd_counter[5] <= 1;
ddr_cs_n_d[5] <= ddr_cs_n;
end
3'd6: begin
cmd_count_en[6] <= 1;
cmd_counter[6] <= 1;
ddr_cs_n_d[6] <= ddr_cs_n;
end
3'd7: begin
cmd_count_en[7] <= 1;
cmd_counter[7] <= 1;
ddr_cs_n_d[7] <= ddr_cs_n;
end
endcase
end
///////////////////////////////////////////////////////////////////////
if (mem_wr_cmd) begin
case (wr_cmd_cnt_ptr)
3'd0: begin
wr_cmd_count_en[0] <= 1;
wr_cmd_counter[0] <= 1;
wr_ddr_cs_n_d[0] <= ddr_cs_n;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -