我也来分享个SDRAM的Verilog垃圾代码
本帖最后由 wye11083 于 2012-7-4 09:09 编辑如下:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 08:02:41 04/23/2012
// Design Name:
// Module Name: SDRController
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module SDRController(
//input GCLK,
//input GRST,
input int_in_GRST,
input int_in_GCLK,
input int_in_GCLK2X,
input int_in_Read_AccessAddr,
input int_in_Write_AccessAddr,
input int_in_Data_Read_Request,
input int_in_Data_Write_Request,
input int_in_Command_Valid,
input int_in_Data_In,
output int_out_Data_Out,
output int_out_Data_Valid,
output int_out_CurrentState, // State -powering -ReadReq:ReadState -WriteReq:WriteState
// -AutoRefresh -Powered on -State Idle
output int_out_IDLE,
//output port_out_Chip_Select,
output port_out_CS,
output port_out_RAS,
output port_out_CAS,
output port_out_WE,
output port_out_BA,
output port_out_A,
inout port_io_Data,
output port_out_CK, // LVDS output
output port_out_CKS,
output port_out_CKE,
output port_out_DQM
);
(* keep = 1 *) reg r_port_io_Data_Out_EN /* synthesis keep = 1 */;
(* keep = 1 *) reg r_port_io_Data_Out /* synthesis keep = 1 */;
reg r_port_io_Data_Out_output_cache;
reg r_port_io_Data_Out_EN_output_cache;
(* keep = 1 *) reg r_port_io_Data_Local_GCLK /* synthesis keep = 1 */;
assign port_io_Data = r_port_io_Data_Out_EN_output_cache ? r_port_io_Data_Out_output_cache : 16'bz;
always @(posedge int_in_GCLK)
begin
r_port_io_Data_Out_output_cache <= r_port_io_Data_Out;
r_port_io_Data_Out_EN_output_cache <= r_port_io_Data_Out_EN;
r_port_io_Data_Local_GCLK <= port_io_Data;
end
// These are the output level registers. No delay indeed.
reg r_int_out_Data_Out;
reg r_int_out_Data_Valid;
assign int_out_Data_Out = r_int_out_Data_Out;
assign int_out_Data_Valid = r_int_out_Data_Valid;
wire ws_DRAM_State_PowerUp = 0;
wire ws_DRAM_State_Startup_Sequence = 1;
wire ws_DRAM_State_CKEValid_Delay = 2;
wire ws_DRAM_State_Setup_MRS_EMRS = 3;
wire ws_DRAM_State_Setup_MRS_EMRS_Delay = 4;
wire ws_DRAM_State_IDLE = 5;
wire ws_DRAM_State_Refresh = 6;
wire ws_DRAM_State_Refresh_Delay = 7;
wire ws_DRAM_State_Bank_Row_Active = 8;
wire ws_DRAM_State_Bank_Row_Active_Delay = 9;
wire ws_DRAM_State_Write_NAP = 10;
wire ws_DRAM_State_Write_NAP_Col = 11;
wire ws_DRAM_State_Write_NAP_WriteData = 12;
wire ws_DRAM_State_Read_NAP = 13;
wire ws_DRAM_State_Read_NAP_Col = 14;
wire ws_DRAM_State_Read_NAP_Col_Delay = 15;
wire ws_DRAM_State_Read_NAP_ReadData = 16;
wire ws_DRAM_State_Precharge_All = 17;
wire ws_DRAM_State_Precharge_All_Delay = 18;
reg rs_DRAM_State = 0;
reg rs_DRAM_Next_State = 0;
reg r_CK_Enable = 0;
reg r_port_out_CKE = 0;
// Time Out Counter Value. Set for time out operation.
reg r_Timeout_Counter_Value = 16'd20000;
// Reset Time Out Counter. Set to 1 before operation then set 0.
reg r_Timeout_Counter_Reset = 0;
// If Timeout_Interrupt is set to 1, the time is out for previous operation.
wire w_Timeout_Interrupt;
// Whenever refresh is required, Request is set 1 until certain refresh cycles occur.
wire w_Refresh_Request;
// Validate refresh counter. This signal must be set 1 for each refresh cycle.
reg r_Refresh_Validate = 0;
// Because we use 16-bit sdram, the CAddr is aligned to real ca
reg r_int_in_AccessAddr = 0;
wire w_Request_RAddr = r_int_in_AccessAddr;
wire w_Request_CAddr = {r_int_in_AccessAddr,3'b0};
wire w_Request_BAddr = r_int_in_AccessAddr;
reg r_Bank0_Address = 0;
reg r_Bank1_Address = 0;
reg r_Bank2_Address = 0;
reg r_Bank3_Address = 0;
wire w_Last_Open_RowAddr = (w_Request_BAddr == 0)?r_Bank0_Address :
(w_Request_BAddr == 1)?r_Bank1_Address :
(w_Request_BAddr == 2)?r_Bank2_Address :
r_Bank3_Address;
reg r_Bank_Open_Status = 0;
wire w_Bank_Is_Open = |r_Bank_Open_Status;
wire w_Current_Bank_Is_Open = (w_Request_BAddr == 0)?r_Bank_Open_Status :
(w_Request_BAddr == 1)?r_Bank_Open_Status :
(w_Request_BAddr == 2)?r_Bank_Open_Status :
r_Bank_Open_Status;
reg r_int_in_Data_Read_Request = 0;
reg r_int_in_Data_Write_Request = 0;
wire w_Data_Read_Request = ^r_int_in_Data_Read_Request;
wire w_Data_Write_Request = ^r_int_in_Data_Write_Request;
// Internal Data Cache. Used for Shift Register.
reg r_int_in_Data_In = 0;
reg r_port_out_CS = 0;
reg r_port_out_RAS = 0;
reg r_port_out_CAS = 0;
reg r_port_out_WE = 0;
reg r_port_out_BA = 0;
reg r_port_out_A = 0;
reg r_port_out_DQM = 0;
reg r_int_out_IDLE = 0;
assign int_out_IDLE = r_int_out_IDLE;
// State -powering -ReadReq:ReadState -WriteReq:WriteState
// -AutoRefresh -Powered on -State Idle
assign int_out_CurrentState = r_int_out_IDLE;
assign int_out_CurrentState = r_port_out_DQM; // 1-powering up, 0-powered up
assign int_out_CurrentState = ~r_port_out_DQM; // 1-powering up, 0-powered up
assign int_out_CurrentState = w_Data_Read_Request;
assign int_out_CurrentState = w_Data_Write_Request;
reg r_ReadState = 0;
reg r_WriteState = 0;
reg r_RefreshState = 0;
assign int_out_CurrentState = r_ReadState;
assign int_out_CurrentState = r_WriteState;
assign int_out_CurrentState = r_RefreshState;
reg rc_DRAM_Latency = 0;
reg rc_DRAM_Latency_Read = 0;
reg rc_DRAM_Latency_Write = 0;
reg rc_DRAM_Precharge_Latency = 0;
reg rc_DRAM_Setup_MRS_EMRS_Latency = 0;
reg rc_DRAM_Refresh_Latency = 0;
always @(posedge int_in_GCLK or negedge int_in_GRST)
begin
if(~int_in_GRST)
begin
r_CK_Enable <= 0;
rs_DRAM_State <= ws_DRAM_State_PowerUp;
r_Timeout_Counter_Value <= 16'd20000;
r_Timeout_Counter_Reset <= 0;
r_port_out_CKE <= 0;
r_port_io_Data_Out_EN <= 0;
r_port_io_Data_Out <= 0;
rc_DRAM_Latency <= 0;
r_port_out_CS <= 0;
r_port_out_RAS <= 0;
r_port_out_CAS <= 0;
r_port_out_WE <= 0;
r_port_out_BA <= 0;
r_port_out_A <= 0;
r_port_out_DQM <= 0;
r_int_in_Data_Read_Request <= 0;
r_int_in_Data_Write_Request <= 0;
r_int_out_IDLE <= 0;
r_int_out_Data_Out <= 0;
r_int_out_Data_Valid <= 0;
r_int_in_Data_In <= 0;
r_Bank_Open_Status <= 0;
r_ReadState <= 0;
r_WriteState <= 0;
r_RefreshState <= 0;
end
else
begin
r_CK_Enable <= 1; // Enable CK output
r_port_io_Data_Out <= r_int_in_Data_In;
case (rs_DRAM_State)
ws_DRAM_State_IDLE:
begin
// Now we are in IDLE mode.
// Track input request and respond to them.
// Current request mode:
// Burst-Read (8 byte for one 8-bit device); Burst-Write (8 byte for one 8-bit device);
// Auto-Refresh (Auto); Command Write;
r_port_out_DQM <= 0;
r_int_out_Data_Valid <= 0;
r_port_io_Data_Out_EN <= 0;
rs_DRAM_Next_State <= ws_DRAM_State_IDLE;
if(w_Refresh_Request)
begin
r_int_out_IDLE <= 0;
if(w_Bank_Is_Open)
rs_DRAM_State <= ws_DRAM_State_Precharge_All;
else
rs_DRAM_State <= ws_DRAM_State_Refresh;
r_RefreshState <= 1;
end
else if(w_Data_Write_Request)
begin
r_int_in_Data_Write_Request <= ~r_int_in_Data_Write_Request;
rs_DRAM_State <= ws_DRAM_State_Write_NAP;
r_int_out_IDLE <= 0;
// Note that address should be latched.
r_int_in_AccessAddr <= int_in_Write_AccessAddr;
r_int_in_Data_In <= int_in_Data_In;
r_WriteState <= 1;
end
else if(w_Data_Read_Request)
begin
r_int_in_Data_Read_Request <= ~r_int_in_Data_Read_Request;
rs_DRAM_State <= ws_DRAM_State_Read_NAP;
r_int_out_IDLE <= 0;
// Note that address should be latched.
r_int_in_AccessAddr <= int_in_Read_AccessAddr;
r_ReadState <= 1;
end
else
begin
rs_DRAM_State <= ws_DRAM_State_IDLE;
r_int_out_IDLE <= 1;
r_ReadState <= 0;
r_WriteState <= 0;
r_RefreshState <= 0;
end
end
ws_DRAM_State_Write_NAP:
begin
// If given bank enable is inactive, then active it
if(~w_Current_Bank_Is_Open)
begin
// Open row then goto Read Col
rs_DRAM_Next_State <= ws_DRAM_State_Write_NAP_Col;
rs_DRAM_State <= ws_DRAM_State_Bank_Row_Active;
end
else
begin
// Otherwise if row address is not changed, read directly.
if(w_Last_Open_RowAddr == w_Request_RAddr)
rs_DRAM_State <= ws_DRAM_State_Write_NAP_Col;
else
begin
// Precharge first then goto active
rs_DRAM_State <= ws_DRAM_State_Precharge_All;
rs_DRAM_Next_State <= ws_DRAM_State_Write_NAP;
end
end
end
ws_DRAM_State_Write_NAP_Col:
begin
r_port_io_Data_Out_EN <= 1;
r_port_out_CS <= 0;
r_port_out_RAS <= 1;
r_port_out_CAS <= 0;
r_port_out_WE <= 0;
r_port_out_BA <= w_Request_BAddr;
r_port_out_A <= {2'b0,1'b0,1'b0,w_Request_CAddr};
r_port_out_A <= 0;
r_int_in_Data_In <= r_int_in_Data_In >> 16;
rs_DRAM_State <= ws_DRAM_State_Write_NAP_WriteData;
rc_DRAM_Latency_Write <= 1;
end
ws_DRAM_State_Write_NAP_WriteData:
begin
r_port_out_CS <= 1;
rc_DRAM_Latency_Write <= rc_DRAM_Latency_Write + 1;
r_int_in_Data_In <= r_int_in_Data_In >> 16;
if(rc_DRAM_Latency_Write == 7)
begin
rs_DRAM_State <= ws_DRAM_State_IDLE;
r_int_out_IDLE <= 1;
end
else
rs_DRAM_State <= rs_DRAM_State;
end
ws_DRAM_State_Read_NAP:
begin
// If given bank enable is inactive, then active it
if(~w_Current_Bank_Is_Open)
begin
// Open row then goto Read Col
rs_DRAM_Next_State <= ws_DRAM_State_Read_NAP_Col;
rs_DRAM_State <= ws_DRAM_State_Bank_Row_Active;
end
else
begin
// Otherwise if row address is not changed, read directly.
if(w_Last_Open_RowAddr == w_Request_RAddr)
rs_DRAM_State <= ws_DRAM_State_Read_NAP_Col;
else
begin
// Precharge first then goto active
rs_DRAM_State <= ws_DRAM_State_Precharge_All;
rs_DRAM_Next_State <= ws_DRAM_State_Read_NAP;
end
end
end
ws_DRAM_State_Read_NAP_Col:
begin
// First send BA command then wait for 2 cycles
// to go to read state.
rc_DRAM_Latency <= 0;
r_port_out_CS <= 0;
r_port_out_RAS <= 1;
r_port_out_CAS <= 0;
r_port_out_WE <= 1;
r_port_out_BA <= w_Request_BAddr;
r_port_out_A <= {2'b0,1'b0,1'b0,w_Request_CAddr};
r_port_out_A <= 0;
rs_DRAM_State <= ws_DRAM_State_Read_NAP_Col_Delay;
end
ws_DRAM_State_Read_NAP_Col_Delay:
begin
// Deassert CS
r_port_out_CS <= 1;
rc_DRAM_Latency_Read <= 0;
rc_DRAM_Latency <= rc_DRAM_Latency + 1;
// Note the timing. CK is half cycle late than GCLK
if(rc_DRAM_Latency == 3)
rs_DRAM_State <= ws_DRAM_State_Read_NAP_ReadData;
else
rs_DRAM_State <= ws_DRAM_State_Read_NAP_Col_Delay;
end
ws_DRAM_State_Read_NAP_ReadData:
begin
rc_DRAM_Latency_Read <= rc_DRAM_Latency_Read + 1;
r_int_out_Data_Out <= {r_port_io_Data_Local_GCLK,r_int_out_Data_Out};
if(rc_DRAM_Latency_Read == 7)
begin
rs_DRAM_State <= ws_DRAM_State_IDLE;
r_int_out_Data_Valid <= 1;
r_int_out_IDLE <= 1;
end
else
r_int_out_Data_Valid <= 0;
end
ws_DRAM_State_Bank_Row_Active:
begin
// First send BA command then wait for 2 cycles
// to go to read state.
rc_DRAM_Latency <= 0;
r_port_out_CS <= 0;
r_port_out_RAS <= 0;
r_port_out_CAS <= 1;
r_port_out_WE <= 1;
r_port_out_BA <= w_Request_BAddr;
case (w_Request_BAddr)
0:
begin
r_Bank0_Address <= r_int_in_AccessAddr;
r_Bank_Open_Status <= 1;
end
1:
begin
r_Bank1_Address <= r_int_in_AccessAddr;
r_Bank_Open_Status <= 1;
end
2:
begin
r_Bank2_Address <= r_int_in_AccessAddr;
r_Bank_Open_Status <= 1;
end
3:
begin
r_Bank3_Address <= r_int_in_AccessAddr;
r_Bank_Open_Status <= 1;
end
endcase
r_port_out_A <= w_Request_RAddr;
r_port_out_A <= 0;
rs_DRAM_State <= ws_DRAM_State_Bank_Row_Active_Delay;
end
ws_DRAM_State_Bank_Row_Active_Delay:
begin
// Deassert CS
r_port_out_CS <= 1;
rc_DRAM_Latency <= rc_DRAM_Latency + 1;
if(rc_DRAM_Latency == 1)
begin
if(rs_DRAM_Next_State == ws_DRAM_State_IDLE)
r_int_out_IDLE <= 1;
else
r_int_out_IDLE <= 0;
rs_DRAM_State <= rs_DRAM_Next_State;
end
else
rs_DRAM_State <= ws_DRAM_State_Bank_Row_Active_Delay;
end
ws_DRAM_State_PowerUp:
begin
r_port_out_DQM <= 1;
r_port_out_CS <= 1;
// Time out counter is in reset state until now.
// Wait for interrupt line.
if(w_Timeout_Interrupt)
begin
// After Start up sequence, enter CKE stable state.
r_Timeout_Counter_Reset <= 1;
r_Timeout_Counter_Value <= 16'd40;
rs_DRAM_State <= ws_DRAM_State_CKEValid_Delay;
r_port_out_CKE <= 1;
end
else
rs_DRAM_State <= ws_DRAM_State_PowerUp;
end
ws_DRAM_State_CKEValid_Delay:
begin
// Wait for some time to assert CKE.
// Goto precharge and return to ws_DRAM_State_Startup_Sequence for further operation
r_Timeout_Counter_Reset <= 0;
rs_DRAM_Next_State <= ws_DRAM_State_Startup_Sequence;
if(w_Timeout_Interrupt)
rs_DRAM_State <= ws_DRAM_State_Precharge_All;
else
rs_DRAM_State <= rs_DRAM_State;
end
ws_DRAM_State_Startup_Sequence:
begin
if(w_Refresh_Request)
rs_DRAM_State <= ws_DRAM_State_Refresh;
else
begin
rs_DRAM_Next_State <= ws_DRAM_State_IDLE;
rs_DRAM_State <= ws_DRAM_State_Setup_MRS_EMRS;
end
end
ws_DRAM_State_Setup_MRS_EMRS:
begin
// First send MRS command then wait for 3 cycles
// to return to prev. state.
r_port_out_CS <= 0;
r_port_out_RAS <= 0;
r_port_out_CAS <= 0;
r_port_out_WE <= 0;
r_port_out_BA <= 0;
// Fixed: CAS=3 BL=8
// A: CAS Latency, A: BL
r_port_out_A <= {6'd0,3'd2,1'b0,3'd3};
r_port_out_A <= 0;
rs_DRAM_State <= ws_DRAM_State_Setup_MRS_EMRS_Delay;
rc_DRAM_Setup_MRS_EMRS_Latency <= 0;
end
ws_DRAM_State_Setup_MRS_EMRS_Delay:
begin
// Deassert CS
r_port_out_CS <= 1;
rc_DRAM_Setup_MRS_EMRS_Latency <= rc_DRAM_Setup_MRS_EMRS_Latency + 1;
if(rc_DRAM_Setup_MRS_EMRS_Latency == 1)
begin
if(rs_DRAM_Next_State == ws_DRAM_State_IDLE)
r_int_out_IDLE <= 1;
else
r_int_out_IDLE <= 0;
rs_DRAM_State <= rs_DRAM_Next_State;
end
else
rs_DRAM_State <= ws_DRAM_State_Setup_MRS_EMRS_Delay;
end
ws_DRAM_State_Refresh:
begin
// First send Refresh command then wait for 9 cycles
// to return to prev. state.
r_port_out_CS <= 0;
r_port_out_RAS <= 0;
r_port_out_CAS <= 0;
r_port_out_WE <= 1;
rs_DRAM_State <= ws_DRAM_State_Refresh_Delay;
r_Refresh_Validate <= 1;
rc_DRAM_Refresh_Latency <= 0;
end
ws_DRAM_State_Refresh_Delay:
begin
// Deassert CS
r_Refresh_Validate <= 0;
r_port_out_CS <= 1;
rc_DRAM_Refresh_Latency <= rc_DRAM_Refresh_Latency + 1;
if(rc_DRAM_Refresh_Latency == 8)
begin
if(rs_DRAM_Next_State == ws_DRAM_State_IDLE)
r_int_out_IDLE <= 1;
else
r_int_out_IDLE <= 0;
rs_DRAM_State <= rs_DRAM_Next_State;
end
else
rs_DRAM_State <= rs_DRAM_State;
end
ws_DRAM_State_Precharge_All:
begin
// First send Precharge command then wait for 2 cycles
// to return to prev. state. Only all bank precharge is
// supported.
r_port_out_CS <= 0;
r_port_out_RAS <= 0;
r_port_out_CAS <= 1;
r_port_out_WE <= 0;
r_port_out_A <= 1;
r_port_out_A <= 0;
r_port_out_A <= 0;
rs_DRAM_State <= ws_DRAM_State_Precharge_All_Delay;
r_Bank_Open_Status <= 0;
rc_DRAM_Precharge_Latency <= 0;
end
ws_DRAM_State_Precharge_All_Delay:
begin
// Deassert CS
r_port_out_CS <= 1;
rc_DRAM_Precharge_Latency <= rc_DRAM_Precharge_Latency + 1;
if(rc_DRAM_Precharge_Latency == 1)
begin
if(rs_DRAM_Next_State == ws_DRAM_State_IDLE)
r_int_out_IDLE <= 1;
else
r_int_out_IDLE <= 0;
rs_DRAM_State <= rs_DRAM_Next_State;
end
else
rs_DRAM_State <= rs_DRAM_State;
end
default:
rs_DRAM_State <= ws_DRAM_State_IDLE; // Default to IDLE state.
endcase
end
end
// Timer used for Time Out operation.
TimeOutCounter timeout_counter(
.int_in_GCLK(int_in_GCLK),
.int_in_GRST(int_in_GRST),
.int_in_TimeOut_Value(r_Timeout_Counter_Value),
.int_in_TimeOut_Hold(1'b1),
.int_in_Count_Reset(r_Timeout_Counter_Reset),
.int_out_TimeOut_Interrupt(w_Timeout_Interrupt)
);
// Auto-Refresh Counter and Control. Use w_Refresh_Request and w_Refresh_Validate to indicate
// Auto-Refresh require state and Auto-Refresh process state.
wire w_Refresh_Interrupt;
reg rc_Refresh_Count;
assign w_Refresh_Request = (rc_Refresh_Count != 0);
always @(posedge int_in_GCLK or negedge int_in_GRST)
begin
if(~int_in_GRST)
begin
rc_Refresh_Count <= 0;
end
else
begin
if(r_Refresh_Validate & (rc_Refresh_Count > 8'h00))
// Dec Counter. Min is 8'h00
begin
if(~w_Refresh_Interrupt)
rc_Refresh_Count <= rc_Refresh_Count + 8'hFF;
else
rc_Refresh_Count <= rc_Refresh_Count;
end
else if(w_Refresh_Interrupt & (rc_Refresh_Count < 8'hFF))
// Inc Counter. Max is 8'hFF.
rc_Refresh_Count <= rc_Refresh_Count + 1;
else
rc_Refresh_Count <= rc_Refresh_Count;
end
end
// Use a counter to indicate how many refresh cycles is to be done.
TimeOutCounter refresh_counter(
.int_in_GCLK(int_in_GCLK),
.int_in_GRST(int_in_GRST),
.int_in_TimeOut_Value(16'd1560),
.int_in_TimeOut_Hold(1'b0),
.int_in_Count_Reset(1'b0),
.int_out_TimeOut_Interrupt(w_Refresh_Interrupt)
);
// CK Output. Note that it's 1/2 cycle late than original clock.
// Because CK reg is set to zero at the beginning, we use posedge of GCLK2X
// is possible to delay output to 1/2 cycle.
reg r_int_CK_TOG;
reg r_port_out_CK;
reg r_port_out_CKS;
reg r_CK_Enable_Delay;
always @(posedge int_in_GCLK2X)
begin
r_CK_Enable_Delay <= r_CK_Enable;
r_port_out_CK <= r_int_CK_TOG;
r_port_out_CKS <= ~r_int_CK_TOG;
if(~r_CK_Enable_Delay)
r_int_CK_TOG <= 0;
else
r_int_CK_TOG <= ~r_int_CK_TOG;
end
always @(posedge int_in_GCLK or negedge int_in_GRST)
begin
if(~int_in_GRST)
begin
r_int_in_Data_Read_Request <= 0;
r_int_in_Data_Write_Request <= 0;
end
else
begin
if(int_in_Data_Read_Request)
r_int_in_Data_Read_Request <= ~r_int_in_Data_Read_Request;
else
r_int_in_Data_Read_Request <= r_int_in_Data_Read_Request;
if(int_in_Data_Write_Request)
r_int_in_Data_Write_Request <= ~r_int_in_Data_Write_Request;
else
r_int_in_Data_Write_Request <= r_int_in_Data_Write_Request;
end
end
reg r_port_out_CS_output_cache;
reg r_port_out_RAS_output_cache;
reg r_port_out_CAS_output_cache;
reg r_port_out_WE_output_cache;
reg r_port_out_BA_output_cache;
reg r_port_out_A_output_cache;
reg r_port_out_DQM_output_cache;
reg r_port_out_CKE_output_cache;
/*reg r_port_out_CK_output_cache;
reg r_port_out_CKS_output_cache;*/
// Delay one cycle
always @(posedge int_in_GCLK)
begin
r_port_out_CS_output_cache <= r_port_out_CS;
r_port_out_RAS_output_cache <= r_port_out_RAS;
r_port_out_CAS_output_cache <= r_port_out_CAS;
r_port_out_WE_output_cache <= r_port_out_WE;
r_port_out_BA_output_cache <= r_port_out_BA;
r_port_out_A_output_cache <= r_port_out_A;
r_port_out_DQM_output_cache <= r_port_out_DQM;
r_port_out_CKE_output_cache <= r_port_out_CKE;
/*r_port_out_CK_output_cache <= r_port_out_CK;
r_port_out_CKS_output_cache <= r_port_out_CKS;*/
end
assign port_out_CS = r_port_out_CS_output_cache;
assign port_out_RAS = r_port_out_RAS_output_cache;
assign port_out_CAS = r_port_out_CAS_output_cache;
assign port_out_WE = r_port_out_WE_output_cache;
assign port_out_BA = r_port_out_BA_output_cache;
assign port_out_A = r_port_out_A_output_cache;
assign port_out_DQM = r_port_out_DQM_output_cache;
assign port_out_CKE = r_port_out_CKE_output_cache;
/*assign port_out_CK = r_port_out_CK_output_cache;
assign port_out_CKS = r_port_out_CKS_output_cache;*/
/*assign port_out_CS = r_port_out_CS;
assign port_out_RAS = r_port_out_RAS;
assign port_out_CAS = r_port_out_CAS;
assign port_out_WE = r_port_out_WE;
assign port_out_BA = r_port_out_BA;
assign port_out_A = r_port_out_A;
assign port_out_DQM = r_port_out_DQM;
assign port_out_CKE = r_port_out_CKE;*/
assign port_out_CK = r_port_out_CK;
assign port_out_CKS = r_port_out_CKS;
//assign port_io_Data = r_port_io_Data_Out_EN ? r_port_io_Data_Out : 'bz;
endmodule
haha,端口都有说明了,自己根据输出延时计算下,然后把CK的延时调调就可以实现在基频上升沿采样数据了。测试尚未出现问题,但是如果供电不稳肯定会出问题。读写采用一个深度的队列,当int_out_CurrentState和int_out_CurrentState为低时就可以发下一条读写指令。
如果要用于不同容量的SDRAM或不同位数的SDRAM,自己修改
// Because we use 16-bit sdram, the CAddr is aligned to real ca
reg r_int_in_AccessAddr = 0;
wire w_Request_RAddr = r_int_in_AccessAddr;
wire w_Request_CAddr = {r_int_in_AccessAddr,3'b0};
wire w_Request_BAddr = r_int_in_AccessAddr;
reg r_Bank0_Address = 0;
reg r_Bank1_Address = 0;
reg r_Bank2_Address = 0;
reg r_Bank3_Address = 0;
wire w_Last_Open_RowAddr = (w_Request_BAddr == 0)?r_Bank0_Address :
(w_Request_BAddr == 1)?r_Bank1_Address :
(w_Request_BAddr == 2)?r_Bank2_Address :
r_Bank3_Address;
这里的地址映射。
刚才少发了一个模块,补上来:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 07:32:44 04/23/2012
// Design Name:
// Module Name: TimeOutCounter
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module TimeOutCounter(
input int_in_GCLK,
input int_in_GRST,
input int_in_TimeOut_Value,
input int_in_TimeOut_Hold, // Active 1
input int_in_Count_Reset, // Active 1
output int_out_TimeOut_Interrupt
);
// When counter exceeds int_in_TimeOut_Value, if int_in_TimeOut_Hold
// then not return to zero until a int_in_Count_Reset event occurs.
// Else counter will return to zero and int_in_Count_Reset is effective too.
reg rc_int_in_TimeOut_Counter;
reg r_int_out_TimeOut_Interrupt;
assign int_out_TimeOut_Interrupt = r_int_out_TimeOut_Interrupt;
always @(posedge int_in_GCLK or negedge int_in_GRST)
begin
if(~int_in_GRST)
begin
rc_int_in_TimeOut_Counter <= 0;
r_int_out_TimeOut_Interrupt <= 0;
end
else
begin
r_int_out_TimeOut_Interrupt <= (rc_int_in_TimeOut_Counter == int_in_TimeOut_Value);
if(rc_int_in_TimeOut_Counter == int_in_TimeOut_Value)
begin
if(~int_in_TimeOut_Hold | int_in_Count_Reset)
rc_int_in_TimeOut_Counter <= 0;
else
rc_int_in_TimeOut_Counter <= rc_int_in_TimeOut_Counter;
end
else
begin
if(int_in_Count_Reset)
rc_int_in_TimeOut_Counter <= 0;
else
rc_int_in_TimeOut_Counter <= rc_int_in_TimeOut_Counter + 1;
end
end
end
endmodule
这个模块用于超时计数,支持异步复位/超时保持/超时自动复位功能,用于启动时序计时。 又见大哥
我有个sdram的想法不知道思路对不对
http://www.amobbs.com/thread-5484270-1-1.html
altera的pll功能xilinx dcm能实现吗? chadusb 发表于 2012-7-4 09:39 static/image/common/back.gif
又见大哥
我有个sdram的想法不知道思路对不对
http://www.amobbs.com/thread-5484270-1-1.html
PLL可以用DCM实现,但是也有代价,DCM只能产生固定的时钟,而且步进有限,只能产生(1-32)/(1-32)这么多个时钟,即1/1,1/2,。。,1/32,2/1,。。,32/32。 补充一个TestBench:
`timescale 1ns / 100ps
////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 10:48:55 07/03/2012
// Design Name: SDRController
// Module Name: D:/USBDevelop/SDRController_tb.v
// Project Name:USBDevelop
// Target Device:
// Tool versions:
// Description:
//
// Verilog Test Fixture created by ISE for module: SDRController
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
////////////////////////////////////////////////////////////////////////////////
module SDRController_tb;
// Inputs
reg int_in_GRST;
reg int_in_GCLK;
reg int_in_GCLK2X;
reg int_in_Read_AccessAddr;
reg int_in_Write_AccessAddr;
reg int_in_Data_Read_Request;
reg int_in_Data_Write_Request;
reg int_in_Command_Valid;
reg int_in_Data_In;
// Outputs
wire int_out_Data_Out;
wire int_out_Data_Valid;
wire int_out_IDLE;
wire port_out_Chip_Select;
wire port_out_CS;
wire port_out_RAS;
wire port_out_CAS;
wire port_out_WE;
wire port_out_BA;
wire port_out_A;
wire port_out_CK;
wire port_out_CKS;
wire port_out_CKE;
wire port_out_DQM;
// Bidirs
wire port_io_Data;
reg r_port_io_Data;
reg r_port_io_Data_EN;
assign port_io_Data = r_port_io_Data_EN?r_port_io_Data:'bz;
// Instantiate the Unit Under Test (UUT)
SDRController uut (
.int_in_GRST(int_in_GRST),
.int_in_GCLK(int_in_GCLK),
.int_in_GCLK2X(int_in_GCLK2X),
.int_in_Read_AccessAddr(int_in_Read_AccessAddr),
.int_in_Write_AccessAddr(int_in_Write_AccessAddr),
.int_in_Data_Read_Request(int_in_Data_Read_Request),
.int_in_Data_Write_Request(int_in_Data_Write_Request),
.int_in_Command_Valid(int_in_Command_Valid),
.int_in_Data_In(int_in_Data_In),
.int_out_Data_Out(int_out_Data_Out),
.int_out_Data_Valid(int_out_Data_Valid),
.int_out_IDLE(int_out_IDLE),
.port_out_Chip_Select(port_out_Chip_Select),
.port_out_CS(port_out_CS),
.port_out_RAS(port_out_RAS),
.port_out_CAS(port_out_CAS),
.port_out_WE(port_out_WE),
.port_out_BA(port_out_BA),
.port_out_A(port_out_A),
.port_io_Data(port_io_Data),
.port_out_CK(port_out_CK),
.port_out_CKS(port_out_CKS),
.port_out_CKE(port_out_CKE),
.port_out_DQM(port_out_DQM)
);
initial begin
// Initialize Inputs
r_port_io_Data_EN = 0;
int_in_GRST = 0;
int_in_GCLK = 1;
int_in_GCLK2X = 1;
int_in_Read_AccessAddr = 0;
int_in_Write_AccessAddr = 0;
int_in_Data_Read_Request = 0;
int_in_Data_Write_Request = 0;
int_in_Command_Valid = 0;
int_in_Data_In = 0;
// Wait 100 ns for global reset to finish
#100;
// Add stimulus here
int_in_GRST = 1;
#200000;
r_port_io_Data_EN=1;
#10;
while(~int_out_IDLE)#10;
#100;
int_in_Read_AccessAddr = 0;
int_in_Data_Read_Request = 1;
#10;
int_in_Data_Read_Request = 0;
#10;
while(~int_out_IDLE)#10;
int_in_Read_AccessAddr = 512;
int_in_Data_Read_Request = 1;
#10;
int_in_Data_Read_Request = 0;
#10;
while(~int_out_IDLE)#10;
int_in_Read_AccessAddr = 32'h00400000;
int_in_Data_Read_Request = 1;
#10;
int_in_Data_Read_Request = 0;
#10;
while(~int_out_IDLE)#10;
r_port_io_Data_EN=0;
int_in_Data_Write_Request = 1;
int_in_Write_AccessAddr = 32'h00400100;
#10;
int_in_Data_Write_Request = 0;
#10;
while(~int_out_IDLE)#10;
int_in_Data_Write_Request = 1;
int_in_Write_AccessAddr = 32'h00000000;
#10;
int_in_Data_Write_Request = 0;
#10;
#1200;
#10;
while(~int_out_IDLE)#10;
#100;
r_port_io_Data_EN=1;
int_in_Read_AccessAddr = 0;
int_in_Data_Read_Request = 1;
#10;
int_in_Data_Read_Request = 0;
#10;
while(~int_out_IDLE)#10;
int_in_Read_AccessAddr = 512;
int_in_Data_Read_Request = 1;
#10;
int_in_Data_Read_Request = 0;
#10;
while(~int_out_IDLE)#10;
int_in_Read_AccessAddr = 32'h01400000;
int_in_Data_Read_Request = 1;
#10;
int_in_Data_Read_Request = 0;
#10;
#18000;
while(~int_out_IDLE)#10;
r_port_io_Data_EN=0;
int_in_Data_Write_Request = 1;
int_in_Write_AccessAddr = 32'h00400100;
#10;
int_in_Data_Write_Request = 0;
#10;
while(~int_out_IDLE)#10;
int_in_Data_Write_Request = 1;
int_in_Write_AccessAddr = 32'h00000000;
#10;
int_in_Data_Write_Request = 0;
#10;
end
always #10 r_port_io_Data = $random;
always #10 int_in_Data_In = {$random,$random,$random,$random};
always #2.5 int_in_GCLK2X = ~int_in_GCLK2X;
always #5 int_in_GCLK = ~int_in_GCLK;
endmodule
另补充一点说明:需要在XST配置属性和MAP配置属性中把IOB Reg Packing全部选中,否则会出现时序异常。GCLK和GCLK2X时钟为同一个DCM或DLL产生的1X和2X时钟,不要移相。经过计算,建立时间可以达到要求,数据正常。另外,到SDRAM的CK端需要调整为Fast Slew。 花2分钟粗粗看了一下,这个一点也不垃圾,有Bank/Row自动激活/预充功能,非常实用。 我看了下代码,看惯了3个模块的通用控制器感觉还是不习惯,呵呵,那个ck是什么端口,还要用lvds接?你那个sdram多大的怎么都是32位地址线,自己修改的话是不是这些地址线,以及映射地址都得改,还有setup_MRS_EMRS(应该是LOAD_MODE吧?)那里也要改?队列深度是不是那个128位的reg?如果把那个队列改大,是不是可以不用fifo就能异步了? chadusb 发表于 2012-7-4 15:52 static/image/common/back.gif
我看了下代码,看惯了3个模块的通用控制器感觉还是不习惯,呵呵,那个ck是什么端口,还要用lvds接?你那个sd ...
CK是SDRAM的时钟线,不需要LVDS,那个接口是接DDR用的,DDR模块正在开发中。用不同的内存需要改的是地址线的映射,而不是地址线。128b是因为我用的16bit的内存,BL=8,因此一次要读进去16字节的数据。这些都可以根据实际情况调整,状态机不需要动,已经测试正常工作的。这些都可以根据情况在状态机中配置,在外面修改接口和相应的读写计数器的。即状态机框架不动,只修改内外的配置寄存器和wire接线。如果你用的是16Mx16的SDRAM,就不用改任何东西,接上去就可以工作。 wye11083 发表于 2012-7-4 21:54 static/image/common/back.gif
CK是SDRAM的时钟线,不需要LVDS,那个接口是接DDR用的,DDR模块正在开发中。用不同的内存需要改的是地址 ...
/*******************************************************************
*Project Name:sdram
*ModuleName :sdram
*Target Device :EP1C6Q240C8
*Clkin :50M
*Desisgner:kang
*Date :2010-12-01
*Version :1.00
*Descriprion :sdram controller
*Additional Comments :sdram controller works at 125M HZ.
*******************************************************************/
module sdram_self(
//input signals
input clk,
input rst,
input wr_req,
input rd_req,
input addr, //from bus
input data_write, //from bus
//output signals
output cs_n,
output cas_n,
output ras_n,
output cke,
output reg ba,
output reg add, //give sdram
output we_n,
output wr_ack,
output rd_ack,
output busy,
output data_read,
output wr_done,
output rd_done,
//inout signals
inout dq
);
//Initial state machine parameters
parameterINIT_NOP =4'd0,
INIT_PRE =4'd1,
INIT_AR =4'd2,
INIT_MRS =4'd3,
INIT_CNT =4'd4,
INIT_DONE=4'd5;
//Work state machine parameters
parameter WORK_IDLE =4'd0,
WORK_ACTIVE =4'd1,
WORK_READ =4'd2,
WORK_RD=4'd3,
WORK_RWAIT =4'd4,
WORK_WRITE =4'd5,
WORK_WD=4'd6,
WORK_TDAL =4'd7,
WORK_AR=4'd8;
//Command parameters
parameter CMD_INIT =5'b01111, //Initial after power on
CMD_NOP =5'b10111, //NOP command
CMD_ACTIVE=5'b10011, //ACTIVE command
CMD_READ =5'b10101, //READ command
CMD_WRITE=5'b10100, //WRITE command
CMD_BURSTSTOP =5'b10110, //BURST stop
CMD_PRECHARGE =5'b10010, //precharge
CMD_AUTOREFRESH=5'b10001, //auto refersh
CMD_LOADMODEREG=5'b10000; //load mode register
//timing parameters
parameterTRP_CLK =4'd4, //precharge
TRFC_CLK =4'd6, //refresh
TMRD_CLK =4'd6, //load mode register
TRCD_CLK =4'd2, //row to column delay
TCL_CLK =4'd3, //cas latency
TREAD_CLK=4'd8, //read
TWRITE_CLK=4'd8, //write
TDAL_CLK =4'd3; //after write,wait clock num
/**********************************************************************
******************from here starts the control code********************
***********************************************************************/
/***********************************************************************
//delay 200us after power on
//this counter depends on the work frequency
//default:125M HZ
***********************************************************************/
//counter_200us
reg counter_200us;
always @(posedge clk or negedge rst)
begin
if(!rst)
counter_200us<=0;
else if(counter_200us<15'd25000)//if 80MHZ,16000
counter_200us<=counter_200us+1'b1;
end
//done_200us
wire done_200us;
assign done_200us=(counter_200us>=15'd25000); //16000,80mhz
/**********************************************************************
//command assignments
//command is made up of cke,cs_n,ras_n,cas_n,we_n
//command's value is produced by the work state machine
**********************************************************************/
reg command;
assign {cke,cs_n,ras_n,cas_n,we_n}=command;
/**********************************************************************
//Initial state machine
//this state machine is only avaliable after power on,and only runs once
//when this state machine runs over,then the controller runs in the work state machine
//
***********************************************************************/
reg init_nextstate; //next state
reg init_state;//current state
reg init_counter; //this counter is used to make delay in the initial state machine
reg init_cmd; //cmd in the initial state machine
reg init_ba; // bank
reg init_addr;//
reg refresh_counter;
always @(posedge clk or negedge rst)
begin
if(!rst) begin
init_cmd<=CMD_INIT;
init_ba<=2'b11;
init_addr<=12'hfff;
init_state<=INIT_NOP;
init_state<=INIT_NOP;
init_counter<=0;
refresh_counter<=0;
end
else begin
case(init_state)
INIT_NOP : //wait 200us after power on, and then go the the next state
begin
init_cmd<=CMD_NOP;
init_ba<=2'b11;
init_addr<=12'hfff;
if(done_200us) init_state<=INIT_PRE;
end
INIT_PRE : //precharge
begin
init_cmd<=CMD_PRECHARGE;
init_ba<=2'b11;
init_addr<=12'hfff;
init_counter<=TRP_CLK;
init_state<=INIT_CNT;
init_nextstate<=INIT_AR;
end
INIT_AR: //auto refresh, in the initial state,we run auto refresh 3 times
begin
init_ba<=2'b11;
init_addr<=12'hfff;
init_counter<=TRFC_CLK;
if(refresh_counter==4'h7)
begin
init_state<=INIT_MRS;
end
else
begin
refresh_counter<=refresh_counter+1'b1;
init_cmd<=CMD_AUTOREFRESH;
init_state<=INIT_CNT;
end
init_nextstate<=INIT_AR;
end
INIT_MRS : //load the mode register
begin
init_cmd<=CMD_AUTOREFRESH;
init_ba<=2'b00;
init_addr<={
2'b00,//a11=0,a10=0;
1'b0, //a9,burst read and write
2'b00,//a8=0;a7=0;
3'b011,//cas latency=3
1'b0, //burst mode set
3'b011//burst data length set,here we use the length of 8
};
init_counter<=TRFC_CLK;
init_state<=INIT_CNT;
init_nextstate<=INIT_DONE;
end
INIT_CNT : //init state machine counter, used to produce delay
begin
init_cmd<=CMD_NOP;
init_ba<=2'b11;
init_addr<=12'hfff;
if(init_counter>4'd1) init_counter<=init_counter-1'b1;
else init_state<=init_nextstate;
end
INIT_DONE: //initial done
init_state<=INIT_DONE;
default:
begin
init_state<=INIT_NOP;
init_ba<=2'b11;
init_addr<=12'hfff;
end
endcase
end
end
wire sign_init_done;
assign sign_init_done=(init_state==INIT_DONE)?1'b1:1'b0;
/*******************************************************************************
//refresh counter
//sdram need refresh every 64ms,and this chip has 4096 columns
//so we has to fresh every 15.625us
*******************************************************************************/
//counter_15us
reg counter_15us;
always @(posedge clk or negedge rst)
begin
if(!rst) counter_15us<=0;
else if(counter_15us>=11'd1875) counter_15us<=0; //11'd1200
else counter_15us<=counter_15us+1'b1;
end
//refresh request and answer back
reg refresh_req;//refresh request
wire refresh_ack;//refresh answer back
always @(posedge clk or negedge rst)
begin
if(!rst) refresh_req<=0;
else if(counter_15us>=1875) refresh_req<=1'b1; //11'd1200
else if(refresh_ack) refresh_req<=0;
end
/*******************************************************************************
//work state machine
//this state machine works at the normal time, including read, write and refresh
//when initial state machine runs over, this machine begin to run
//
*******************************************************************************/
reg work_state; //current state
reg work_counter; //work counter, used to make delay
reg wr_n; //when write,wr_n=0;when read,wr_n=1;
reg oe;
always @(posedge clk or negedge rst)
begin
if(!rst) begin
command<=CMD_INIT;
ba<=2'b11;
add=12'hfff;
work_state<=WORK_IDLE;
work_counter<=0;
end
else if(sign_init_done)//when initial state machine done, work state machine begin to run
begin
case(work_state)
WORK_IDLE : //in the idle state, we will enter autorefresh or active state as the next state
begin
command<=CMD_NOP;
ba<=2'b11;
add=12'hfff;
work_counter<=0;
if(refresh_req)
begin
work_state<=WORK_AR;
end
else if(wr_req)
//begin
//if((prior_rowadd==addr)&&is_prior_wr) work_state<=WORK_WRITE;
//else
begin
work_state<=WORK_ACTIVE;
wr_n<=0;
end
//end
else if(rd_req)
//begin
//if((prior_rowadd==addr)&&is_prior_rd) work_state<=WORK_READ;
//else
begin
work_state<=WORK_ACTIVE;
wr_n<=1'b1;
end
//end
else work_state<=WORK_IDLE;
end
/*************************************************************************/
WORK_ACTIVE : //write the row address,and wait TRCD_CLK clks
begin
ba<=addr;
add=addr;
if(work_counter>=TRCD_CLK)
begin
if(wr_n) work_state<=WORK_READ;
else work_state<=WORK_WRITE;
work_counter<=0;
end
else begin
if(work_counter==0) command<=CMD_ACTIVE;
else command<=CMD_NOP;
work_state<=WORK_ACTIVE;
work_counter<=work_counter+1'b1;
end
end
/*************************************************************************/
WORK_READ : //read. wait TCL_CLK clks, then enter WORK_RD
begin
ba<=addr;
add<={
4'b0100, //A10=1;allow precharge after write
addr //column address
};
if(work_counter>=(TCL_CLK))
begin
work_state<=WORK_RD;
work_counter<=0;
end
else begin
work_state<=WORK_READ;
work_counter<=work_counter+1'b1;
end
if(work_counter==0) command<=CMD_READ;
else command<=CMD_NOP;
end
/*************************************************************************/
WORK_RD: //read data
begin
command<=CMD_NOP;
if(work_counter>=(TREAD_CLK-1'b1))
begin
work_state<=WORK_RWAIT;
work_counter<=0;
end
else begin
work_state<=WORK_RD;
work_counter<=work_counter+1'b1;
end
end
/*************************************************************************/
WORK_RWAIT : //read wait
begin
command<=CMD_NOP;
if(work_counter>=(TRP_CLK))
begin
work_state<=WORK_IDLE;
work_counter<=0;
end
else begin
work_state<=WORK_RWAIT;
work_counter<=work_counter+1'b1;
end
end
/*************************************************************************/
WORK_WRITE : //write
begin
command<=CMD_WRITE;
ba<=addr;
add<={
4'b0100, //A10=1;allow precharge after write
addr //column address
};
work_state<=WORK_WD;
end
/*************************************************************************/
WORK_WD: //write data
begin
command<=CMD_NOP;
if(work_counter>=(TWRITE_CLK-1'b1))
begin
work_state<=WORK_TDAL;
work_counter<=0;
end
else begin
work_state<=WORK_WD;
work_counter<=work_counter+1'b1;
end
end
/*************************************************************************/
WORK_TDAL : //write delay
begin
command<=CMD_NOP;
if(work_counter>=TDAL_CLK)
begin
work_state<=WORK_IDLE;
work_counter<=0;
end
else begin
work_state<=WORK_TDAL;
work_counter<=work_counter+1'b1;
end
end
/*************************************************************************/
WORK_AR: //auto refresh
begin
if(work_counter==0) command<=CMD_AUTOREFRESH;
else command<=CMD_NOP;
ba<=2'b11;
add<=12'hfff;
if(work_counter==TRFC_CLK)
begin
work_state<=WORK_IDLE;
work_counter<=0;
end
elsebegin
work_state<=WORK_AR;
work_counter<=work_counter+1'b1;
end
end
default:
begin
command<=CMD_NOP;
work_state<=WORK_IDLE;
work_counter<=0;
end
endcase
end
else //when in initial state, all parameters are equaled to the initial state
begin
command<=init_cmd;
ba<=init_ba;
add<=init_addr;
work_counter<=0;
end
end
/*************************************************************************/
assign busy=(sign_init_done&&(work_state==WORK_IDLE))?1'b0:1'b1;
assign refresh_ack=(work_state==WORK_AR);
assign wr_ack=(work_state==WORK_WD);
assign rd_ack=(work_state==WORK_RD);
assign wr_done=(work_state==WORK_TDAL)&&(work_counter==5'd0);
assign rd_done=(work_state==WORK_RWAIT)&&(work_counter==5'd0);
assign data_read=dq;
assign dq=((work_state==WORK_WD)||(work_state==WORK_WRITE)||(work_state==WORK_TDAL))?data_write:16'hzzzz;
endmodule
我觉得这个SDRAM读写的还不错的,但是就是不会写testbench,麻烦帮忙给看看,多谢了 单字节写入
8字节写入
全页写入
均支持么? fishplj2000 发表于 2012-8-7 17:16 static/image/common/back.gif
单字节写入
8字节写入
全页写入
这个SDRAM模块目前已经不再支持了。考虑到效率,仅支持BL=8。而且延时也需要调整。如果有需要,你可以等待半个月,届时我应该会推出8端口(4读4写)高速DDR控制器(理论最大带宽98%)。 wye11083 发表于 2012-8-7 23:06 static/image/common/back.gif
这个SDRAM模块目前已经不再支持了。考虑到效率,仅支持BL=8。而且延时也需要调整。如果有需要,你可以等 ...
{:victory:} 牛
要顶
代码里面的reg和wire的命名都好长啊!下次能不能精简些?{:lol:} 顶一下,也在弄SDRAM,做TFT显示,我做的是BL=full page的 顶一下,{:biggrin:} 这个必须要顶。 这个厉害!! mark下 最近在学习FPGA 谢谢分享,先收藏
页:
[1]