OpenCores
URL https://opencores.org/ocsvn/openarty/openarty/trunk

Subversion Repositories openarty

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /openarty/trunk/rtl
    from Rev 21 to Rev 24
    Reverse comparison

Rev 21 → Rev 24

/wbddrsdram.v
2,9 → 2,16
//
// Filename: wbddrsdram.v
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
// Project: A wishbone controlled DDR3 SDRAM memory controller.
// Used in: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose:
// Purpose: To control a DDR3-1333 (9-9-9) memory from a wishbone bus.
// In our particular implementation, there will be two command
// clocks (2.5 ns) per FPGA clock (i_clk) at 5 ns, and 64-bits transferred
// per FPGA clock. However, since the memory is focused around 128-bit
// word transfers, attempts to transfer other than adjacent 64-bit words
// will (of necessity) suffer stalls. Please see the documentation for
// more details of how this controller works.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
70,133 → 77,62
`define DDR_BABITS 3 // BABITS are really from 18:16, they are 3 bits
`define DDR_ADDR_BITS 14
//
 
//
module wbddrsdram(i_clk, i_reset,
// Wishbone inputs
i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data,
o_wb_ack, o_wb_stall, o_wb_data,
o_ddr_reset_n, o_ddr_cke,
o_ddr_cs_n, o_ddr_ras_n, o_ddr_cas_n, o_ddr_we_n,
o_ddr_dqs, o_ddr_dm, o_ddr_odt, o_ddr_bus_oe,
o_ddr_addr, o_ddr_ba, o_ddr_data, i_ddr_data);
parameter CKRBITS = 13, // Bits in CKREFI4
CKREFI = 13'd1560, // 4 * 7.8us at 200 MHz clock
CKRFC = 320,
CKWR = 3,
CKRP = 11, // (=tRTP)Time from precharge to open command
CKCAS = 11, // CAS Latency, tCL
CKXPR = CKRFC+5+2, // Clocks per tXPR timeout
BUSREG= 2+CKCAS,
BUSNOW= 3+CKCAS;
input i_clk, i_reset;
i_wb_sel,
// Wishbone outputs
o_wb_ack, o_wb_stall, o_wb_data,
// Memory command wires
o_ddr_reset_n, o_ddr_cke, o_ddr_bus_oe,
o_ddr_cmd_a, o_ddr_cmd_b,
// And the data wires to go with them ....
o_ddr_data, i_ddr_data);
// These parameters are not really meant for adjusting from the
// top level. These are more internal variables, recorded here
// so that things can be automatically adjusted without much
// problem.
parameter CKRP = 3;
parameter BUSNOW = 4, BUSREG = BUSNOW-1;
// The commands (above) include (in this order):
// o_ddr_cs_n, o_ddr_ras_n, o_ddr_cas_n, o_ddr_we_n,
// o_ddr_dqs, o_ddr_dm, o_ddr_odt
input i_clk, // *MUST* be at 200 MHz for this to work
i_reset;
// Wishbone inputs
input i_wb_cyc, i_wb_stb, i_wb_we;
input [25:0] i_wb_addr;
input [31:0] i_wb_data;
// Wishbone outputs
output reg o_wb_ack;
output reg o_wb_stall;
output reg [31:0] o_wb_data;
// DDR3 RAM Controller
output reg o_ddr_reset_n, o_ddr_cke;
// Control outputs
output wire o_ddr_cs_n, o_ddr_ras_n, o_ddr_cas_n,o_ddr_we_n;
// DQS outputs:set to 3'b010 when data is active, 3'b100 (i.e. 2'bzz) ow
output wire o_ddr_dqs;
output reg o_ddr_dm;
output reg o_ddr_odt;
output wire o_ddr_bus_oe;
// Address outputs
output wire [13:0] o_ddr_addr;
output wire [2:0] o_ddr_ba;
// And the data inputs and outputs
output reg [31:0] o_ddr_data;
input [31:0] i_ddr_data;
input i_wb_cyc, i_wb_stb, i_wb_we;
input [24:0] i_wb_addr; // Identifies a 64-bit word of interest
input [63:0] i_wb_data;
input [7:0] i_wb_sel;
// Wishbone responses/outputs
output reg o_wb_ack, o_wb_stall;
output reg [63:0] o_wb_data;
// DDR memory command wires
output reg o_ddr_reset_n, o_ddr_cke, o_ddr_bus_oe;
// CMDs are:
// 4 bits of CS, RAS, CAS, WE
// 3 bits of bank
// 14 bits of Address
// 1 bit of DQS (strobe active, or not)
// 4 bits of mask (one per byte)
// 1 bit of ODT
// ----
// 27 bits total
output wire [26:0] o_ddr_cmd_a, o_ddr_cmd_b;
output reg [63:0] o_ddr_data;
input [63:0] i_ddr_data;
 
reg drive_dqs;
 
// The pending transaction
reg [31:0] r_data;
reg r_pending, r_we;
reg [25:0] r_addr;
reg [13:0] r_row;
reg [2:0] r_bank;
reg [9:0] r_col;
reg [1:0] r_sub;
reg r_move; // It was accepted, and can move to next stage
 
// The pending transaction, one further into the pipeline. This is
// the stage where the read/write command is actually given to the
// interface if we haven't stalled.
reg [31:0] s_data;
reg s_pending, s_we; // , s_match;
reg [25:0] s_addr;
reg [13:0] s_row, s_nxt_row;
reg [2:0] s_bank, s_nxt_bank;
reg [9:0] s_col;
reg [1:0] s_sub;
 
// Can the pending transaction be satisfied with the current (ongoing)
// transaction?
reg m_move, m_match, m_pending, m_we;
reg [25:0] m_addr;
reg [13:0] m_row;
reg [2:0] m_bank;
reg [9:0] m_col;
reg [1:0] m_sub;
 
// Can we preload the next bank?
reg [13:0] r_nxt_row;
reg [2:0] r_nxt_bank;
 
reg need_close_bank, need_close_this_bank,
last_close_bank, maybe_close_next_bank,
last_maybe_close,
need_open_bank, last_open_bank, maybe_open_next_bank,
last_maybe_open,
valid_bank, last_valid_bank;
reg [(`DDR_CMDLEN-1):0] close_bank_cmd, activate_bank_cmd,
maybe_close_cmd, maybe_open_cmd, rw_cmd;
reg [1:0] rw_sub;
reg rw_we;
 
wire w_this_closing_bank, w_this_opening_bank,
w_this_maybe_close, w_this_maybe_open,
w_this_rw_move;
reg last_closing_bank, last_opening_bank;
wire w_need_close_this_bank, w_need_open_bank,
w_r_valid, w_s_valid, w_s_match;
//////////
//
// tWTR = 7.5
// tRRD = 7.5
// tREFI= 7.8
// tFAW = 45
// tRTP = 7.5
// tCKE = 5.625
// tRFC = 160
// tRP = 13.5
// tRAS = 36
// tRCD = 13.5
//
// RESET:
// 1. Hold o_reset_n = 1'b0; for 200 us, or 40,000 clocks (65536 perhaps?)
// Hold cke low during this time as well
// The clock should be free running into the chip during this time
// Leave command in NOOP state: {cs,ras,cas,we} = 4'h7;
// ODT must be held low
// 2. Hold cke low for another 500us, or 100,000 clocks
// 3. Raise CKE, continue outputting a NOOP for
// tXPR, tDLLk, and tZQInit
// 4. Load MRS2, wait tMRD
// 4. Load MRS3, wait tMRD
// 4. Load MRS1, wait tMOD
// Before using the SDRAM, we'll need to program at least 3 of the mode
// registers, if not all 4.
// tMOD clocks are required to program the mode registers, during which
// time the RAM must be idle.
// Reset Logic
//
// NOOP: CS low, RAS, CAS, and WE high
 
//
//////////
//
//
// Reset logic should be simple, and is given as follows:
// note that it depends upon a ROM memory, reset_mem, and an address into that
// memory: reset_address. Each memory location provides either a "command" to
205,7 → 141,7
// be set to idle, or whether the command is instead left as it was.
reg reset_override, reset_ztimer, maintenance_override;
reg [4:0] reset_address;
reg [(`DDR_CMDLEN-1):0] reset_cmd, cmd, refresh_cmd,
reg [(`DDR_CMDLEN-1):0] reset_cmd, cmd_a, cmd_b, refresh_cmd,
maintenance_cmd;
reg [24:0] reset_instruction;
reg [16:0] reset_timer;
240,51 → 176,15
reset_timer <= reset_instruction[16:0];
end
wire [16:0] w_ckXPR, w_ckRST, w_ckRP,
w_ckRFC_first;
wire [2:0] w_ckCAS_MR2, w_ckCAS_MR0, w_ckCAS, w_ckFIVE;
wire [16:0] w_ckXPR, w_ckRFC_first;
wire [13:0] w_MR0, w_MR1, w_MR2;
assign w_ckXPR = CKXPR;
assign w_ckRST = 4;
assign w_ckRP = CKRP-2;
/* verilator lint_off WIDTH */
assign w_ckCAS = CKCAS;
/* verilator lint_on WIDTH */
assign w_ckRFC_first = CKRFC-2-9+8;
assign w_ckFIVE = 3'h5;
assign w_ckCAS_MR2 = w_ckFIVE-3'h5; // w_ckCAS-3'h5;
assign w_ckCAS_MR0 = w_ckFIVE-3'h4; // w_ckCAS-3'h4;
assign w_MR2 = { 3'h0, 2'b00, 1'b0, 1'b0, 1'b1, w_ckCAS_MR2, 3'b0 };
assign w_MR1 = {
1'h0, // Reserved for Future Use (RFU)
1'b0, // Qoff - output buffer enabled
1'b1, // TDQS ... enabled
1'b0, // RFU
1'b0, // High order bit, Rtt_Nom (3'b011)
1'b0, // RFU
//
1'b0, // Disable write-leveling
1'b1, // Mid order bit of Rtt_Nom
1'b0, // High order bit of Output Drvr Impedence Ctrl
2'b0, // Additive latency = 0
1'b1, // Low order bit of Rtt_Nom
1'b0, // DIC set to 2'b00
1'b0 // MRS1, DLL enable
};
assign w_MR0 = {
1'b0, // Reserved for future use
1'b0, // PPD control, (slow exit(DLL off))
3'b1, // Write recovery for auto precharge
1'b0, // DLL Reset (No)
//
1'b0, // TM mode normal
w_ckCAS_MR0, // High 3-bits, CAS latency (=4'b1110=4'd5,tCL=11)
//
1'b0, // Read burst type = nibble sequential
(CKCAS>11)? 1'b1:1'b0, // Low bit of cas latency
2'b0 // Burst length = 8 (Fixed)
};
assign w_MR0 = 14'h0420;
assign w_MR1 = 14'h0044;
assign w_MR2 = 14'h0040;
assign w_ckXPR = 17'd68; // Table 68, p186
assign w_ckRFC_first = 17'd30; // i.e. 64 nCK, or ckREFI
always @(posedge i_clk)
// DONE, TIMER, RESET, CKE,
if (i_reset)
reset_instruction <= { 4'h4, `DDR_NOOP, 17'd40_000 };
else if (reset_ztimer) case(reset_address) // RSTDONE, TIMER, CKE, ??
294,41 → 194,36
5'h1: reset_instruction <= { 4'h6, `DDR_NOOP, 17'd100_000 };
// 3. Assert CKE, wait minimum of Reset CKE Exit time
5'h2: reset_instruction <= { 4'h7, `DDR_NOOP, w_ckXPR };
// 4. Look MR2. (1CK, no TIMER)
5'h3: reset_instruction <= { 4'h3, `DDR_NOOP, 3'h2, w_MR2 };
5'h4: reset_instruction <= { 4'h3, `DDR_MRSET, 3'h2, w_MR2 };
5'h5: reset_instruction <= { 4'h3, `DDR_NOOP, 3'h2, w_MR2 };
// 3. Wait 4 clocks (tMRD)
5'h6: reset_instruction <= { 4'h7, `DDR_NOOP, 17'h02 };
// 5. Set MR1
5'h7: reset_instruction <= { 4'h3, `DDR_NOOP, 3'h1, w_MR1 };
5'h8: reset_instruction <= { 4'h3, `DDR_MRSET, 3'h1, w_MR1 };
5'h9: reset_instruction <= { 4'h3, `DDR_NOOP, 3'h1, w_MR1 };
// 7. Wait another 4 clocks
5'ha: reset_instruction <= { 4'h7, `DDR_NOOP, 17'h02 };
// 8. Send MRS0
5'hb: reset_instruction <= { 4'h3, `DDR_NOOP, 3'h0, w_MR0 };
5'hc: reset_instruction <= { 4'h3, `DDR_MRSET, 3'h0, w_MR0 };
5'hd: reset_instruction <= { 4'h3, `DDR_NOOP, 3'h0, w_MR0 };
// 9. Wait tMOD, is max(12 clocks, 15ns)
5'he: reset_instruction <= { 4'h7, `DDR_NOOP, 17'h0a };
// 10. Issue a ZQCL command to start ZQ calibration, A10 is high
5'hf: reset_instruction <= { 4'h3, `DDR_ZQS, 6'h0, 1'b1, 10'h0};
//11.Wait for both tDLLK and tZQinit completed, both are 512 cks
5'h10: reset_instruction <= { 4'h7, `DDR_NOOP, 17'd512 };
// 4. Set MR2. (4 nCK, no TIMER, but needs a NOOP cycle)
5'h3: reset_instruction <= { 4'h3, `DDR_MRSET, 3'h2, w_MR2 };
5'h4: reset_instruction <= { 4'h3, `DDR_NOOP, 17'h00 };
// 5. Set MR1. (4 nCK, no TIMER, but needs a NOOP cycle)
5'h5: reset_instruction <= { 4'h3, `DDR_MRSET, 3'h1, w_MR1 };
5'h6: reset_instruction <= { 4'h3, `DDR_NOOP, 17'h00 };
// 6. Set MR0
5'h7: reset_instruction <= { 4'h3, `DDR_MRSET, 3'h0, w_MR0 };
// 7. Wait 12 clocks
5'h8: reset_instruction <= { 4'h7, `DDR_NOOP, 17'd10 };
// 8. Issue a ZQCL command to start ZQ calibration, A10 is high
5'h9: reset_instruction <= { 4'h3, `DDR_ZQS, 6'h0, 1'b1, 10'h0};
//11.Wait for both tDLLK and tZQinit completed, both are
// 512 cks. Of course, since every one of these commands takes
// two clocks, we wait for half as many clocks (minus two for
// our timer logic)
5'ha: reset_instruction <= { 4'h7, `DDR_NOOP, 17'd254 };
// 12. Precharge all command
5'h11: reset_instruction <= { 4'h3, `DDR_PRECHARGE, 6'h0, 1'b1, 10'h0 };
// 13. Wait for the precharge to complete
5'h12: reset_instruction <= { 4'h7, `DDR_NOOP, w_ckRP };
5'hb: reset_instruction <= { 4'h3, `DDR_PRECHARGE, 6'h0, 1'b1, 10'h0 };
// 13. Wait for the precharge to complete. A count of one,
// will have us waiting (1+2)*2 or 6 clocks, so we should be
// good here.
5'hc: reset_instruction <= { 4'h7, `DDR_NOOP, 17'd1 };
// 14. A single Auto Refresh commands
5'h13: reset_instruction <= { 4'h3, `DDR_REFRESH, 17'h00 };
5'hd: reset_instruction <= { 4'h3, `DDR_REFRESH, 17'h00 };
// 15. Wait for the auto refresh to complete
5'h14: reset_instruction <= { 4'h7, `DDR_NOOP, w_ckRFC_first };
// Two Auto Refresh commands
5'he: reset_instruction <= { 4'h7, `DDR_NOOP, w_ckRFC_first };
default:
reset_instruction <={4'hb, `DDR_NOOP, 17'd00_000 };
endcase
// reset_instruction <= reset_mem[reset_address];
 
initial reset_address = 5'h0;
always @(posedge i_clk)
336,36 → 231,216
reset_address <= 5'h1;
else if ((reset_ztimer)&&(reset_override))
reset_address <= reset_address + 5'h1;
 
//////////
//
// initial reset_mem =
// 0. !DONE, TIMER,RESET_N=0, CKE=0, CMD = NOOP, TIMER = 200us ( 40,000)
// 1. !DONE, TIMER,RESET_N=1, CKE=0, CMD = NOOP, TIMER = 500us (100,000)
// 2. !DONE, TIMER,RESET_N=1, CKE=1, CMD = NOOP, TIMER = (Look me up)
// 3. !DONE,!TIMER,RESET_N=1, CKE=1, CMD = MODE, MRS
// 4. !DONE,!TIMER,RESET_N=1, CKE=1, CMD = NOOP, TIMER = tMRS
// 5. !DONE,!TIMER,RESET_N=1, CKE=1, CMD = MODE, MRS3
// 6. !DONE,!TIMER,RESET_N=1, CKE=1, CMD = NOOP, TIMER = tMRS
// 7. !DONE,!TIMER,RESET_N=1, CKE=1, CMD = MODE, MRS1
// 8. !DONE,!TIMER,RESET_N=1, CKE=1, CMD = NOOP, TIMER = tMRS
// 9. !DONE,!TIMER,RESET_N=1, CKE=1, CMD = MODE, MRS1
// 10. !DONE,!TIMER,RESET_N=1, CKE=1, CMD = NOOP, TIMER = tMOD
// 11. !DONE,!TIMER,RESET_N=1, CKE=1, (Pre-charge all)
// 12. !DONE,!TIMER,RESET_N=1, CKE=1, (wait)
// 13. !DONE,!TIMER,RESET_N=1, CKE=1, (Auto-refresh)
// 14. !DONE,!TIMER,RESET_N=1, CKE=1, (Auto-refresh)
// 15. !DONE,!TIMER,RESET_N=1, CKE=1, (wait)
//
// Refresh Logic
//
//
//////////
//
//
//
// Okay, let's investigate when we need to do a refresh. Our plan will be to
// do a single refreshes every tREFI seconds. We will not push off refreshes,
// nor pull them in--for simplicity. tREFI = 7.8us, but it is a parameter
// in the number of clocks. In our case, 7.8us / 5ns = 1560 clocks (not nCK!)
//
// Note that 160ns are needed between refresh commands (JEDEC, p172), or
// 32 clocks @200MHz. After this time, no more refreshes will be needed for
// (1560-32) clocks (@ 200 MHz).
//
// This logic is very similar to the refresh logic, both use a memory as a
// script.
//
reg need_refresh;
reg refresh_ztimer;
reg [16:0] refresh_counter;
reg [2:0] refresh_addr;
reg [23:0] refresh_instruction;
always @(posedge i_clk)
if (reset_override)
refresh_addr <= 3'hf;
else if (refresh_ztimer)
refresh_addr <= refresh_addr + 3'h1;
else if (refresh_instruction[`DDR_RFBEGIN])
refresh_addr <= 3'h0;
 
always @(posedge i_clk)
if (reset_override)
begin
refresh_ztimer <= 1'b1;
refresh_counter <= 17'd0;
end else if (!refresh_ztimer)
begin
refresh_ztimer <= (refresh_counter == 17'h1);
refresh_counter <= (refresh_counter - 17'h1);
end else if (refresh_instruction[`DDR_RFTIMER])
begin
refresh_ztimer <= 1'b0;
refresh_counter <= refresh_instruction[16:0];
end
 
wire [16:0] w_ckREFI;
assign w_ckREFI = 17'd1560; // == 6240/4
 
wire [16:0] w_ckREFI_left, w_ckRFC_nxt, w_wait_for_idle,
w_precharge_to_refresh;
 
// We need to wait for the bus to become idle from whatever state
// it is in. The difficult time for this measurement is assuming
// a write was just given. In that case, we need to wait for the
// write to complete, and then to wait an additional tWR (write
// recovery time) or 6 nCK clocks from the end of the write. This
// works out to seven idle bus cycles from the time of the write
// command, or a count of 5 (7-2).
assign w_wait_for_idle = 17'd5; //
assign w_precharge_to_refresh = 17'd1; // = 3-2
assign w_ckREFI_left[16:0] = 17'd1560 // The full interval
-17'd32 // Min what we've already waited
-w_wait_for_idle
-w_precharge_to_refresh-17'd12;
assign w_ckRFC_nxt[16:0] = 17'd32-17'd2;
 
always @(posedge i_clk)
if (refresh_ztimer)
case(refresh_addr)//NEED-REFRESH, HAVE-TIMER, BEGIN(start-over)
// First, a number of clocks needing no refresh
3'h0: refresh_instruction <= { 3'h2, `DDR_NOOP, w_ckREFI_left };
// Then, we take command of the bus and wait for it to be
// guaranteed idle
3'h1: refresh_instruction <= { 3'h6, `DDR_NOOP, w_wait_for_idle };
// Once the bus is idle, all commands complete, and a minimum
// recovery time given, we can issue a precharge all command
3'h2: refresh_instruction <= { 3'h4, `DDR_PRECHARGE, 17'h0400 };
// Now we need to wait tRP = 3 clocks (6 nCK)
3'h3: refresh_instruction <= { 3'h6, `DDR_NOOP, w_precharge_to_refresh };
3'h4: refresh_instruction <= { 3'h4, `DDR_REFRESH, 17'h00 };
3'h5: refresh_instruction <= { 3'h6, `DDR_NOOP, w_ckRFC_nxt };
default:
refresh_instruction <= { 3'h1, `DDR_NOOP, 17'h00 };
endcase
 
// Note that we don't need to check if (reset_override) here since
// refresh_ztimer will always be true if (reset_override)--in other
// words, it will be true for many, many, clocks--enough for this
// logic to settle out.
always @(posedge i_clk)
if (refresh_ztimer)
refresh_cmd <= refresh_instruction[20:0];
always @(posedge i_clk)
if (refresh_ztimer)
need_refresh <= refresh_instruction[`DDR_NEEDREFRESH];
 
 
/*
input i_clk, i_reset;
// Wishbone inputs
input i_wb_cyc, i_wb_stb, i_wb_we;
input [25:0] i_wb_addr;
input [31:0] i_wb_data;
// Wishbone outputs
output reg o_wb_ack;
output reg o_wb_stall;
output reg [31:0] o_wb_data;
// DDR3 RAM Controller
output reg o_ddr_reset_n, o_ddr_cke;
// Control outputs
output wire o_ddr_cs_n, o_ddr_ras_n, o_ddr_cas_n,o_ddr_we_n;
// DQS outputs:set to 3'b010 when data is active, 3'b100 (i.e. 2'bzz) ow
output wire o_ddr_dqs;
output reg o_ddr_odt;
output wire o_ddr_bus_oe;
// Address outputs
output wire [13:0] o_ddr_addr;
output wire [2:0] o_ddr_ba;
// And the data inputs and outputs
output reg [31:0] o_ddr_data;
input [31:0] i_ddr_data;
*/
 
 
reg [1:0] drive_dqs;
// Our chosen timing doesn't require any more resolution than one
// bus clock for ODT. (Of course, this really isn't necessary, since
// we aren't using ODT as per the MRx registers ... but we keep it
// around in case we change our minds later.)
reg ddr_odt;
reg [7:0] ddr_dm;
 
// The pending transaction
reg [63:0] r_data;
reg r_pending, r_we;
reg [24:0] r_addr;
reg [13:0] r_row;
reg [2:0] r_bank;
reg [9:0] r_col;
reg r_sub;
reg [7:0] r_sel;
 
// The pending transaction, one further into the pipeline. This is
// the stage where the read/write command is actually given to the
// interface if we haven't stalled.
reg [63:0] s_data;
reg s_pending, s_we; // , s_match;
reg [24:0] s_addr;
reg [13:0] s_row, s_nxt_row;
reg [2:0] s_bank, s_nxt_bank;
reg [9:0] s_col;
reg s_sub;
reg [7:0] s_sel;
 
// Can the pending transaction be satisfied with the current (ongoing)
// transaction?
reg m_move, m_match, m_pending, m_we;
reg [24:0] m_addr;
reg [13:0] m_row;
reg [2:0] m_bank;
reg [9:0] m_col;
reg [1:0] m_sub;
 
// Can we preload the next bank?
reg [13:0] r_nxt_row;
reg [2:0] r_nxt_bank;
 
reg need_close_bank, need_close_this_bank,
last_close_bank, maybe_close_next_bank,
last_maybe_close,
need_open_bank, last_open_bank, maybe_open_next_bank,
last_maybe_open,
valid_bank;
reg [(`DDR_CMDLEN-1):0] close_bank_cmd, activate_bank_cmd,
maybe_close_cmd, maybe_open_cmd, rw_cmd;
reg rw_sub;
reg rw_we;
 
wire w_this_closing_bank, w_this_opening_bank,
w_this_maybe_close, w_this_maybe_open,
w_this_rw_move;
reg last_closing_bank, last_opening_bank;
wire w_need_close_this_bank, w_need_open_bank,
w_r_valid, w_s_valid, w_s_match;
 
//////////
//
//
// Open Banks
//
//
//////////
//
//
//
// Let's keep track of any open banks. There are 8 of them to keep track of.
//
// A precharge requires 3 clocks at 200MHz to complete, 2 clocks at 100MHz.
//
// A precharge requires 3 clocks at 200MHz to complete.
// An activate also requires 3 clocks at 200MHz to complete.
// Precharges are not allowed until the maximum of:
// 2 clocks (200 MHz) after a read command
// 8 clocks after a write command
//
//
reg need_refresh;
 
wire w_precharge_all;
reg [CKRP:0] bank_status [0:7];
reg [13:0] bank_address [0:7];
375,7 → 450,7
reg [7:0] bank_closed;
 
wire [3:0] write_recycle_clocks;
assign write_recycle_clocks = CKWR+4+4;
assign write_recycle_clocks = 4'h8;
 
initial bank_open = 0;
initial bank_closed = 8'hff;
447,15 → 522,15
bank_status[close_bank_cmd[16:14]]
<= { bank_status[close_bank_cmd[16:14]][(CKRP-1):0], 1'b0 };
bank_open[close_bank_cmd[16:14]] <= 1'b0;
// bank_status[close_bank_cmd[16:14]][0] <= 1'b0;
end else if (need_open_bank)
begin
bank_status[activate_bank_cmd[16:14]]
<= { bank_status[activate_bank_cmd[16:14]][(CKRP-1):0], 1'b1 };
// bank_status[activate_bank_cmd[16:14]][0] <= 1'b1;
bank_closed[activate_bank_cmd[16:14]] <= 1'b0;
end else if (valid_bank)
;
; // Read/write command was issued. This neither opens
// nor closes any banks, and hence it needs no logic
// here
else if (maybe_close_next_bank)
begin
bank_status[maybe_close_cmd[16:14]]
465,183 → 540,66
begin
bank_status[maybe_open_cmd[16:14]]
<= { bank_status[maybe_open_cmd[16:14]][(CKRP-1):0], 1'b1 };
// bank_status[activate_bank_cmd[16:14]][0] <= 1'b1;
bank_closed[maybe_open_cmd[16:14]] <= 1'b0;
end
end
 
always @(posedge i_clk)
// if (cmd[22:19] == `DDR_ACTIVATE)
if (w_this_opening_bank)
bank_address[activate_bank_cmd[16:14]]
<= activate_bank_cmd[13:0];
else if (!w_this_maybe_open)
else if (w_this_maybe_open)
bank_address[maybe_open_cmd[16:14]]
<= maybe_open_cmd[13:0];
 
 
//////////
//
//
// Okay, let's investigate when we need to do a refresh. Our plan will be to
// do 4 refreshes every tREFI*4 seconds. tREFI = 7.8us, but its a parameter
// in the number of clocks so that we can handle both 100MHz and 200MHz clocks.
// Data BUS information
//
// Note that 160ns are needed between refresh commands (JEDEC, p172), or
// 320 clocks @200MHz, or equivalently 160 clocks @100MHz. Thus to issue 4
// of these refresh cycles will require 4*320=1280 clocks@200 MHz. After this
// time, no more refreshes will be needed for 6240 clocks.
//
// Let's think this through:
// REFRESH_COST = (n*(320)+24)/(n*1560)
//
//////////
//
//
reg refresh_ztimer;
reg [16:0] refresh_counter;
reg [2:0] refresh_addr;
reg [23:0] refresh_instruction;
always @(posedge i_clk)
if (reset_override)
refresh_addr <= 3'hf;
else if (refresh_ztimer)
refresh_addr <= refresh_addr + 3'h1;
else if (refresh_instruction[`DDR_RFBEGIN])
refresh_addr <= 3'h0;
 
always @(posedge i_clk)
if (reset_override)
begin
refresh_ztimer <= 1'b1;
refresh_counter <= 17'd0;
end else if (!refresh_ztimer)
begin
refresh_ztimer <= (refresh_counter == 17'h1);
refresh_counter <= (refresh_counter - 17'h1);
end else if (refresh_instruction[`DDR_RFTIMER])
begin
refresh_ztimer <= 1'b0;
refresh_counter <= refresh_instruction[16:0];
end
 
`ifdef QUADRUPLE_REFRESH
// REFI4 = 13'd6240
wire [16:0] w_ckREFIn, w_ckREFRst, w_wait_for_idle,
w_precharge_to_refresh;
assign w_wait_for_idle = 5+CKCAS;
assign w_precharge_to_refresh = CKRP-1;
assign w_ckREFIn[(CKRBITS-1): 0] = CKREFI4-5*CKRFC-2-10;
assign w_ckREFIn[ 16:(CKRBITS)] = 0;
assign w_ckREFRst = CKRFC-2-12;
 
always @(posedge i_clk)
if (refresh_ztimer)
case(refresh_addr)//NEED-RFC, HAVE-TIMER,
4'h0: refresh_instruction <= { 3'h2, `DDR_NOOP, w_ckREFIn };
// 17'd10 = time to complete write, plus write recovery time
// minus two (cause we can't count zero or one)
// = WL+4+tWR-2 = 10
// = 5+4+3-2 = 10
4'h1: refresh_instruction <= { 3'h6, `DDR_NOOP, w_wait_for_idle };
4'h2: refresh_instruction <= { 3'h4, `DDR_PRECHARGE, 17'h0400 };
4'h3: refresh_instruction <= { 3'h6, `DDR_NOOP, w_precharge_to_refresh };
4'h4: refresh_instruction <= { 3'h4, `DDR_REFRESH, 17'h00 };
4'h5: refresh_instruction <= { 3'h6, `DDR_NOOP, w_ckRFC };
4'h6: refresh_instruction <= { 3'h4, `DDR_REFRESH, 17'h00 };
4'h7: refresh_instruction <= { 3'h6, `DDR_NOOP, w_ckRFC };
4'h8: refresh_instruction <= { 3'h4, `DDR_REFRESH, 17'h00 };
4'h9: refresh_instruction <= { 3'h6, `DDR_NOOP, w_ckRFC };
4'ha: refresh_instruction <= { 3'h4, `DDR_REFRESH, 17'h00 };
4'hb: refresh_instruction <= { 3'h6, `DDR_NOOP, w_ckRFC };
4'hc: refresh_instruction <= { 3'h2, `DDR_NOOP, w_ckREFRst };
default:
refresh_instruction <= { 3'h1, `DDR_NOOP, 17'h00 };
endcase
`else
wire [16:0] w_ckREFI_left, w_ckRFC_nxt, w_wait_for_idle,
w_precharge_to_refresh;
assign w_wait_for_idle = 5+CKCAS;
assign w_precharge_to_refresh = CKRP-2;
assign w_ckREFI_left[16:0] = { 4'h0, CKREFI }-CKRFC-9
-w_wait_for_idle
-w_precharge_to_refresh;
// assign w_ckREFI_left[16:13] = 0;
assign w_ckRFC_nxt[8:0] = CKRFC+9'h2;
assign w_ckRFC_nxt[16:9] = 0;
 
always @(posedge i_clk)
if (refresh_ztimer)
case(refresh_addr)//NEED-REFRESH, HAVE-TIMER, BEGIN(start-over)
3'h0: refresh_instruction <= { 3'h2, `DDR_NOOP, w_ckREFI_left };
3'h1: refresh_instruction <= { 3'h6, `DDR_NOOP, w_wait_for_idle };
3'h2: refresh_instruction <= { 3'h4, `DDR_PRECHARGE, 17'h0400 };
3'h3: refresh_instruction <= { 3'h6, `DDR_NOOP, w_precharge_to_refresh };
3'h4: refresh_instruction <= { 3'h4, `DDR_REFRESH, 17'h00 };
3'h5: refresh_instruction <= { 3'h6, `DDR_NOOP, w_ckRFC_nxt };
default:
refresh_instruction <= { 3'h1, `DDR_NOOP, 17'h00 };
endcase
`endif
 
always @(posedge i_clk)
if (reset_override)
refresh_cmd <= { `DDR_NOOP, w_ckREFI_left };
else if (refresh_ztimer)
refresh_cmd <= refresh_instruction[20:0];
always @(posedge i_clk)
if (reset_override)
need_refresh <= 1'b0;
else if (refresh_ztimer)
need_refresh <= refresh_instruction[`DDR_NEEDREFRESH];
 
 
// Our purpose here is to keep track of when the data bus will be
// active. This is separate from the FIFO which will contain the
// data to be placed on the bus (when so placed), in that this is
// a group of shift registers--every position has a location in time,
// and time always moves forward. The FIFO, on the other hand, only
// moves forward when data moves onto the bus.
//
//
// Let's track: when will our bus be active? When will we be reading or
// writing?
//
//
 
reg [BUSNOW:0] bus_active, bus_read, bus_new, bus_ack;
reg [1:0] bus_subaddr [BUSNOW:0];
reg [BUSNOW:0] bus_subaddr, bus_odt;
initial bus_active = 0;
initial bus_ack = 0;
always @(posedge i_clk)
begin
bus_active[BUSNOW:0] <= { bus_active[(BUSNOW-1):0], 1'b0 };
bus_read[BUSNOW:0] <= { bus_read[(BUSNOW-1):0], 1'b0 }; // Drive the d-bus?
// Drive the d-bus?
bus_read[BUSNOW:0] <= { bus_read[(BUSNOW-1):0], 1'b0 };
// Is this a new command? i.e., the start of a transaction?
bus_new[BUSNOW:0] <= { bus_new[(BUSNOW-1):0], 1'b0 };
bus_odt[BUSNOW:0] <= { bus_odt[(BUSNOW-1):0], 1'b0 };
// Will this position on the bus get a wishbone acknowledgement?
bus_ack[BUSNOW:0] <= { bus_ack[(BUSNOW-1):0], 1'b0 };
//bus_mask[8:0] <= { bus_mask[7:0], 1'b1 }; // Write this value?
bus_subaddr[8] <= bus_subaddr[7];
bus_subaddr[7] <= bus_subaddr[6];
bus_subaddr[6] <= bus_subaddr[5];
bus_subaddr[5] <= bus_subaddr[4];
bus_subaddr[4] <= bus_subaddr[3];
bus_subaddr[3] <= bus_subaddr[2];
bus_subaddr[2] <= bus_subaddr[1];
bus_subaddr[1] <= bus_subaddr[0];
bus_subaddr[0] <= 2'h3;
//
bus_subaddr[BUSNOW:0] <= { bus_subaddr[(BUSNOW-1):0], 1'b1 };
 
bus_ack[5] <= (bus_ack[4])&&
((bus_subaddr[5] != bus_subaddr[4])
||(bus_new[4]));
if (w_this_rw_move)
begin
bus_active[3:0]<= 4'hf; // Once per clock
bus_subaddr[3] <= 2'h0;
bus_subaddr[2] <= 2'h1;
bus_subaddr[1] <= 2'h2;
bus_active[1:0]<= 2'h3; // Data transfers in two clocks
bus_subaddr[1] <= 1'h0;
bus_new[{ 2'b0, rw_sub }] <= 1'b1;
bus_ack[3:0] <= 4'h0;
bus_ack[1:0] <= 2'h0;
bus_ack[{ 2'b0, rw_sub }] <= 1'b1;
 
bus_read[3:0] <= (rw_we)? 4'h0:4'hf;
bus_read[1:0] <= (rw_we)? 2'h0:2'h3;
bus_odt[3:0]<= (rw_we)? 4'he:4'h0; // Data transfers in 2 clks
end else if ((s_pending)&&(!pipe_stall))
begin
if (bus_subaddr[3] == s_sub)
bus_ack[4] <= 1'b1;
if (bus_subaddr[2] == s_sub)
bus_ack[3] <= 1'b1;
if (bus_subaddr[1] == s_sub)
bus_ack[2] <= 1'b1;
if (bus_subaddr[0] == s_sub)
651,8 → 609,12
 
// Need to set o_wb_dqs high one clock prior to any read.
always @(posedge i_clk)
drive_dqs <= (|bus_active[BUSREG:(BUSREG-1)])
&&(~(|bus_read[BUSREG:(BUSREG-1)]));
begin
drive_dqs[1] <= (bus_active[(BUSREG)])
&&(!bus_read[(BUSREG)]);
drive_dqs[0] <= (bus_active[BUSREG:(BUSREG-1)] != 2'b00)
&&(bus_read[BUSREG:(BUSREG-1)] == 2'b00);
end
 
//
//
665,10 → 627,6
pre_valid <= 1'b0;
else if (need_refresh)
pre_valid <= 1'b0;
else if (w_this_rw_move)
pre_valid <= 1'b0;
else if (bus_active[0])
pre_valid <= 1'b0;
else
pre_valid <= 1'b1;
 
683,7 → 641,7
assign w_s_match = (s_pending)&&(r_pending)&&(r_we == s_we)
&&(r_row == s_row)&&(r_bank == s_bank)
&&(r_col == s_col)
&&(r_sub > s_sub);
&&(r_sub)&&(!s_sub);
 
reg pipe_stall;
always @(posedge i_clk)
697,8 → 655,8
pipe_stall <= (r_pending)&&(((!w_r_valid)||(valid_bank))&&(!w_s_match));
o_wb_stall <= (r_pending)&&(((!w_r_valid)||(valid_bank))&&(!w_s_match));
end else begin // if (pipe_stall)
pipe_stall <= (s_pending)&&((!w_s_valid)||(valid_bank)||(r_move)||(last_valid_bank));
o_wb_stall <= (s_pending)&&((!w_s_valid)||(valid_bank)||(r_move)||(last_valid_bank));
pipe_stall <= (s_pending)&&((!w_s_valid)||(valid_bank));
o_wb_stall <= (s_pending)&&((!w_s_valid)||(valid_bank));
end
if (need_refresh)
o_wb_stall <= 1'b1;
708,14 → 666,22
r_we <= i_wb_we;
r_addr <= i_wb_addr;
r_data <= i_wb_data;
r_row <= i_wb_addr[25:12];
r_bank <= i_wb_addr[11:9];
r_col <= { i_wb_addr[8:2], 3'b000 }; // 9:2
r_sub <= i_wb_addr[1:0];
r_row <= i_wb_addr[24:11]; // 14 bits row address
r_bank <= i_wb_addr[10:8];
r_col <= { i_wb_addr[7:1], 3'b000 }; // 10 bits Caddr
r_sub <= i_wb_addr[0]; // Select which 64-bit word
r_sel <= i_wb_sel;
 
// i_wb_addr[0] is the 8-bit byte selector of 16-bits (ignored)
// i_wb_addr[1] is the 16-bit half-word selector of 32-bits (ignored)
// i_wb_addr[2] is the 32-bit word selector of 64-bits (ignored)
// i_wb_addr[3] is the 64-bit long word selector of 128-bits
 
// pre-emptive work
r_nxt_row <= (i_wb_addr[11:9]==3'h7)?i_wb_addr[25:12]+14'h1:i_wb_addr[25:12];
r_nxt_bank <= i_wb_addr[11:9]+3'h1;
r_nxt_row <= (i_wb_addr[10:8]==3'h7)
? (i_wb_addr[24:11]+14'h1)
: i_wb_addr[24:11];
r_nxt_bank <= i_wb_addr[10:8]+3'h1;
end
 
if (~pipe_stall)
728,12 → 694,11
s_bank <= r_bank;
s_col <= r_col;
s_sub <= r_sub;
s_sel <= (r_we)?(~r_sel):8'h00;
 
// pre-emptive work
s_nxt_row <= r_nxt_row;
s_nxt_bank <= r_nxt_bank;
 
// s_match <= w_s_match;
end
end
 
779,9 → 744,8
 
 
valid_bank <= ((w_r_valid)||((pipe_stall)&&(w_s_valid)))
&&(!last_valid_bank)&&(!r_move)
// &&(!last_valid_bank)&&(!r_move)
&&(!w_this_rw_move);
last_valid_bank <= r_move;
 
if ((s_pending)&&(pipe_stall))
rw_cmd[`DDR_CSBIT:`DDR_WEBIT] <= (s_we)?`DDR_WRITE:`DDR_READ;
794,9 → 758,9
else
rw_cmd[`DDR_WEBIT-1:0] <= { r_bank, 3'h0, 1'b0, r_col };
if ((s_pending)&&(pipe_stall))
rw_sub <= 2'b11 - s_sub;
rw_sub <= 1'b1 - s_sub;
else
rw_sub <= 2'b11 - r_sub;
rw_sub <= 1'b1 - r_sub;
if ((s_pending)&&(pipe_stall))
rw_we <= s_we;
else
854,38 → 818,49
last_closing_bank <= 1'b0;
last_maybe_open <= 1'b0;
last_maybe_close <= 1'b0;
r_move <= 1'b0;
if (maintenance_override) // Command from either reset or
cmd <= maintenance_cmd; // refresh logic
else if (need_close_bank)
cmd_a <= { `DDR_NOOP, 17'h00 };
cmd_b <= { `DDR_NOOP, rw_cmd[(`DDR_WEBIT-1):0] };
 
if (maintenance_override)
begin // Command from either reset or refresh logic
cmd_a <= maintenance_cmd;
// cmd_b <= { `DDR_NOOP, ...
end else if (need_close_bank)
begin
cmd <= close_bank_cmd;
cmd_a <= close_bank_cmd;
// cmd_b <= { `DDR_NOOP, ...}
last_closing_bank <= 1'b1;
end else if (need_open_bank)
begin
cmd <= activate_bank_cmd;
cmd_a <= activate_bank_cmd;
// cmd_b <={`DDR_NOOP, ...}
last_opening_bank <= 1'b1;
end else if (valid_bank)
begin
cmd <= rw_cmd;
r_move <= 1'b1;
cmd_a <= {(rw_cmd[(`DDR_WEBIT)])?`DDR_READ:`DDR_NOOP,
rw_cmd[(`DDR_WEBIT-1):0] };
cmd_b <= {(rw_cmd[(`DDR_WEBIT)])?`DDR_NOOP:`DDR_WRITE,
rw_cmd[(`DDR_WEBIT-1):0] };
end else if (maybe_close_next_bank)
begin
cmd <= maybe_close_cmd;
cmd_a <= maybe_close_cmd;
// cmd_b <= {`DDR_NOOP, ... }
last_maybe_close <= 1'b1;
end else if (maybe_open_next_bank)
begin
cmd <= maybe_open_cmd;
cmd_a <= maybe_open_cmd;
// cmd_b <= {`DDR_NOOP, ... }
last_maybe_open <= 1'b1;
end else
cmd <= { `DDR_NOOP, rw_cmd[(`DDR_WEBIT-1):0] };
cmd_a <= { `DDR_NOOP, rw_cmd[(`DDR_WEBIT-1):0] };
end
 
`define LGFIFOLN 4
`define FIFOLEN 16
reg [(`LGFIFOLN-1):0] bus_fifo_head, bus_fifo_tail;
reg [31:0] bus_fifo_data [0:(`FIFOLEN-1)];
reg [1:0] bus_fifo_sub [0:(`FIFOLEN-1)];
reg [63:0] bus_fifo_data [0:(`FIFOLEN-1)];
reg [7:0] bus_fifo_sel [0:(`FIFOLEN-1)];
reg bus_fifo_sub [0:(`FIFOLEN-1)];
reg bus_fifo_new [0:(`FIFOLEN-1)];
reg pre_ack;
 
895,68 → 870,47
always @(posedge i_clk)
begin
pre_ack <= 1'b0;
o_ddr_dm <= 1'b0;
if (reset_override)
begin
bus_fifo_head <= {(`LGFIFOLN){1'b0}};
bus_fifo_tail <= {(`LGFIFOLN){1'b0}};
o_ddr_dm <= 1'b0;
end else begin
if ((s_pending)&&(!pipe_stall))
bus_fifo_head <= bus_fifo_head + 1'b1;
 
o_ddr_dm <= (bus_active[BUSREG])&&(!bus_read[BUSREG]);
if (w_bus_fifo_read_next_transaction)
begin
bus_fifo_tail <= bus_fifo_tail + 1'b1;
pre_ack <= 1'b1;
o_ddr_dm <= 1'b0;
end
end
bus_fifo_data[bus_fifo_head] <= s_data;
bus_fifo_sub[bus_fifo_head] <= s_sub;
bus_fifo_new[bus_fifo_head] <= w_this_rw_move;
 
//
// if ((s_pending)&&(!pipe_stall)&&(!nxt_valid))
// nxt_fifo_data <= s_data;
// nxt_fifo_sub <= s_sub;
// nxt_fifo_new <= w_this_rw_move;
// nxt_valid <= 1'b1;
// bus_fifo_head <= bus_fifo_head+1;
// bus_fifo_tail <= bus_fifo_tail+1;
// else if (w_bus_fifo_read_next_transaction)
// nxt_fifo_data <= bus_fifo_data[bus_fifo_tail]
// nxt_fifo_sub <= bus_fifo_data[bus_fifo_tail]
// nxt_fifo_new <= bus_fifo_data[bus_fifo_tail]
// nxt_valid <= (bus_fifo_tail+1 == bus_fifo_head);
//
// if ((!valid)||(w_bus_fifo_next_read_transaction))
// nxt_ <= bus_fifo_x
bus_fifo_sel[bus_fifo_head] <= s_sel;
end
 
 
assign o_ddr_cs_n = cmd[`DDR_CSBIT];
assign o_ddr_ras_n = cmd[`DDR_RASBIT];
assign o_ddr_cas_n = cmd[`DDR_CASBIT];
assign o_ddr_we_n = cmd[`DDR_WEBIT];
assign o_ddr_dqs = drive_dqs;
assign o_ddr_addr = cmd[(`DDR_ADDR_BITS-1):0];
assign o_ddr_ba = cmd[(`DDR_BABITS+`DDR_ADDR_BITS-1):`DDR_ADDR_BITS];
always @(posedge i_clk)
o_ddr_data <= bus_fifo_data[bus_fifo_tail];
assign w_precharge_all = (cmd[`DDR_CSBIT:`DDR_WEBIT]==`DDR_PRECHARGE)
&&(o_ddr_addr[10]); // 5 bits
always @(posedge i_clk)
ddr_dm <= (bus_ack[BUSREG])? bus_fifo_sel[bus_fifo_tail]
: ((!bus_read[BUSREG])? 8'hff: 8'h00);
always @(posedge i_clk)
o_ddr_bus_oe <= (bus_active[BUSREG])&&(!bus_read[BUSREG]);
 
assign o_ddr_bus_oe = drive_dqs; // ~bus_read[BUSNOW];
// First, or left, command
assign o_ddr_cmd_a = { cmd_a, drive_dqs[1], ddr_dm[7:4], ddr_odt };
// Second, or right, command of two
assign o_ddr_cmd_b = { cmd_b, drive_dqs[0], ddr_dm[3:0], ddr_odt };
 
assign w_precharge_all = (cmd_a[`DDR_CSBIT:`DDR_WEBIT]==`DDR_PRECHARGE)
&&(cmd_a[10]);
 
// ODT must be in high impedence while reset_n=0, then it can be set
// to low or high. As per spec, ODT = 0 during reads
always @(posedge i_clk)
o_ddr_odt <= (bus_active[BUSREG-3])&&(!bus_read[BUSREG-3])
||(bus_active[BUSREG-4])&&(!bus_read[BUSREG-4])
||((w_this_rw_move)&&(rw_we)&&(CKCAS<4))
||(CKCAS>3)&&(bus_active[BUSREG-5])&&(!bus_read[BUSREG-5]);
ddr_odt <= bus_odt[BUSREG];
 
always @(posedge i_clk)
o_wb_ack <= pre_ack;
/xioddrserdes.v
0,0 → 1,134
////////////////////////////////////////////////////////////////////////////////
//
// Filename: xioddrserdes.v
//
// Project: A wishbone controlled DDR3 SDRAM memory controller.
//
// Purpose:
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
module xioddrserdes(i_clk_fast, i_clk_fast_inv, i_clk_slow, i_reset,
i_oe, i_data, o_data, io_pin);
input i_clk_fast, i_clk_fast_inv, i_clk_slow, i_reset;
input i_oe;
input [7:0] i_data;
output wire [7:0] o_data;
inout io_pin;
 
wire feedback;
wire oe_for_fabric__unconnected;
wire [1:0] local_shiftout__unconnected;
wire local_tbyte_out__unconnected;
wire send_to_iob;
wire oe_for_iob;
wire [1:0] iserdes_shiftout__unconnected;
 
OSERDESE2 #(
.DATA_RATE_OQ("DDR"),
.DATA_RATE_TQ("BUF"),
.DATA_WIDTH(8), // 8 data wires sent per clkdiv
.INIT_OQ(1'b1),
.SERDES_MODE("MASTER"),
//
.TRISTATE_WIDTH(1),
.INIT_TQ(1'b1),
.TBYTE_CTL("FALSE"),
.TBYTE_SRC("FALSE")
) oserdes_i(
.CLK(i_clk_fast),
.CLKDIV(i_clk_slow),
.OCE(1'b1),
.OFB(feedback),
.OQ(send_to_iob),
.RST(i_reset),
//
.TCE(1'b1),
.TQ(oe_for_iob),
.TFB(oe_for_fabric__unconnected),
.T1(~i_oe), .T2(~i_oe), .T3(~i_oe), .T4(~i_oe),
//
.SHIFTOUT1(local_shiftout__unconnected[0]),
.SHIFTOUT2(local_shiftout__unconnected[1]),
.SHIFTIN1(1'b0),
.SHIFTIN2(1'b0),
.TBYTEIN(1'b0),
.TBYTEOUT(local_tbyte_out__unconnected),
//
// And now for the actual data we wish to send
//
.D1(i_data[0]), .D2(i_data[1]),
.D3(i_data[2]), .D4(i_data[3]),
.D5(i_data[4]), .D6(i_data[5]),
.D7(i_data[6]), .D8(i_data[7])
);
 
IOBUF iobuf_i(
.T(oe_for_iob),
.I(send_to_iob),
.IO(io_pin),
.O(input_from_iobuf));
 
ISERDESE2 #(
.DATA_RATE("DDR"),
.DATA_WIDTH(8), // 8 data wires sent per clkdiv
.INTERFACE_TYPE("OVERSAMPLE"),
.IOBDELAY("NONE"),
.NUM_CE(1),
.OFB_USED("FALSE"),
.SERDES_MODE("MASTER")
) iserdes_i(
.BITSLIP(1'b0),
.CE1(1'b1),
.CE2(1'b1),
.CLK(i_clk_fast),
.CLKB(i_clk_fast_inv),
.CLKDIV(i_clk_slow),
.CLKDIVP(1'b0), // Only used in MEMORY_DDR3 mode?
.D(input_from_iobuf),
.DDLY(1'b0),
.DYNCLKDIVSEL(1'b0),
.DYNCLKSEL(1'b0),
.O(iserdes_unconnected_output),
.OCLK(i_clk_fast),
.OCLKB(i_clk_fast_inv),
.OFB(feedback),
.Q1(o_data[0]), .Q2(o_data[1]),
.Q3(o_data[2]), .Q4(o_data[3]),
.Q5(o_data[4]), .Q6(o_data[5]),
.Q7(o_data[6]), .Q8(o_data[7]),
.RST(i_reset),
.SHIFTIN1(1'b0), .SHIFTIN2(1'b0),
.SHIFTOUT1(iserdes_shiftout__unconnected[0]),
.SHIFTOUT2(iserdes_shiftout__unconnected[1])
);
 
endmodule
 
/fastmaster.v
90,10 → 90,8
// The Quad SPI Flash
o_qspi_cs_n, o_qspi_sck, o_qspi_dat, i_qspi_dat, o_qspi_mod,
// The DDR3 SDRAM
o_ddr_reset_n, o_ddr_cke,
o_ddr_cs_n, o_ddr_ras_n, o_ddr_cas_n, o_ddr_we_n,
o_ddr_dqs, o_ddr_dm, o_ddr_odt, o_ddr_bus_oe,
o_ddr_addr, o_ddr_ba, o_ddr_data, i_ddr_data,
o_ddr_reset_n, o_ddr_cke, o_ddr_bus_oe,
o_ddr_cmd_a, o_ddr_cmd_b, o_ddr_data, i_ddr_data,
// The SD Card
o_sd_sck, o_sd_cmd, o_sd_data, i_sd_cmd, i_sd_data, i_sd_detect,
// Ethernet control (MDIO) lines
128,14 → 126,10
input [3:0] i_qspi_dat;
output wire [1:0] o_qspi_mod;
// DDR3 RAM controller
output wire o_ddr_reset_n, o_ddr_cke,
o_ddr_cs_n, o_ddr_ras_n, o_ddr_cas_n,o_ddr_we_n;
output wire o_ddr_dqs;
output wire o_ddr_dm, o_ddr_odt, o_ddr_bus_oe;
output wire [13:0] o_ddr_addr;
output wire [2:0] o_ddr_ba;
output wire [31:0] o_ddr_data;
input [31:0] i_ddr_data;
output wire o_ddr_reset_n, o_ddr_cke, o_ddr_bus_oe;
output wire [26:0] o_ddr_cmd_a, o_ddr_cmd_b;
output wire [63:0] o_ddr_data;
input [63:0] i_ddr_data;
// The SD Card
output wire o_sd_sck;
output wire o_sd_cmd;
915,13 → 909,16
//
//
`ifdef SDRAM_ACCESS
wire [63:0] w_ram_wide_data;
wbddrsdram #(13,13'd1520) rami(i_clk, i_rst,
wb_cyc, (wb_stb)&&(ram_sel), wb_we, wb_addr[25:0], wb_data,
ram_ack, ram_stall, ram_data,
o_ddr_reset_n, o_ddr_cke,
o_ddr_cs_n, o_ddr_ras_n, o_ddr_cas_n, o_ddr_we_n,
o_ddr_dqs, o_ddr_dm, o_ddr_odt, o_ddr_bus_oe,
o_ddr_addr, o_ddr_ba, o_ddr_data, i_ddr_data);
wb_cyc, (wb_stb)&&(ram_sel), wb_we, wb_addr[24:0],
{ wb_data, wb_data }, (wb_addr[25])? 8'hf0:8'h0f,
ram_ack, ram_stall, w_ram_wide_data,
o_ddr_reset_n, o_ddr_cke, o_ddr_bus_oe,
o_ddr_cmd_a, o_ddr_cmd_b, o_ddr_data, i_ddr_data);
 
// assign ram_data = (wb_addr[25])?w_ram_wide_data[63:32]:w_ram_wide_data[
assign ram_data = w_ram_wide_data[31:0];
`else
assign ram_data = 32'h00;
assign ram_stall = 1'b0;
/fasttop.v
110,21 → 110,22
 
`define FULLCLOCK
// Build our master clock
wire i_clk, clk_for_ddr, clk2_unused, enet_clk, clk_analyzer,
clk_feedback, clk_locked, clk_analyzer_b;
wire i_clk, clk_for_ddr, mem_serial_clk, mem_serial_clk_inv,
enet_clk, clk_halfspeed, clk_feedback, clk_locked, clk_unused;
PLLE2_BASE #(
.BANDWIDTH("OPTIMIZED"), // OPTIMIZED, HIGH, LOW
.CLKFBOUT_PHASE(0.0), // Phase offset in degrees of CLKFB, (-360-360)
.CLKIN1_PERIOD(10.0), // Input clock period in ns to ps resolution
.CLKFBOUT_PHASE(0.0), // Phase off. in deg of CLKFB,(-360-360)
.CLKIN1_PERIOD(10.0), // Input clock period in ns resolution
`ifdef FULLCLOCK
// CLKOUT0_DIVIDE - CLKOUT5_DIVIDE: divide amount for each CLKOUT(1-128)
// CLKOUT0_DIVIDE - CLKOUT5_DIVIDE:
// divide amount for each CLKOUT(1-128)
.CLKFBOUT_MULT(8), // Multiply value for all CLKOUT (2-64)
.CLKOUT0_DIVIDE(4), // 200 MHz
.CLKOUT1_DIVIDE(4), // 200 MHz clock for DDR memory
.CLKOUT2_DIVIDE(8), // 100 MHz
.CLKOUT3_DIVIDE(32), // 25 MHz
.CLKOUT4_DIVIDE(1), // 800 MHz
.CLKOUT5_DIVIDE(1),
.CLKOUT1_DIVIDE(1), // 800 MHz clock for DDR memory
.CLKOUT2_DIVIDE(1), // 800 MHz clock to run DDR I/O
.CLKOUT3_DIVIDE(1), // 800MHz clk inv to run DDR I/O
.CLKOUT4_DIVIDE(8), // 100 MHz
.CLKOUT5_DIVIDE(32), // 25 MHz
`else
// 100*64/40 = 160 -- the fastest speed where the UART will
// still work at 4MBaud. Others will still support 115200
135,10 → 136,10
.CLKFBOUT_MULT(8), // Multiply value for all CLKOUT (2-64)
.CLKOUT0_DIVIDE(5), // 160 MHz
.CLKOUT1_DIVIDE(5), // 160 MHz //Clock too slow for DDR mem
.CLKOUT2_DIVIDE(10), // 80 MHz
.CLKOUT3_DIVIDE(40), // 20 MHz
.CLKOUT4_DIVIDE(1), // 40 MHz
.CLKOUT5_DIVIDE(1),
.CLKOUT2_DIVIDE(5), // 160 MHz // Clock too slow for DDR
.CLKOUT3_DIVIDE(5), // 160 MHz // Clock too slow for DDR
.CLKOUT4_DIVIDE(20), // 40 MHz
.CLKOUT5_DIVIDE(5),
`endif
// CLKOUT0_DUTY_CYCLE -- Duty cycle for each CLKOUT
.CLKOUT0_DUTY_CYCLE(0.5),
151,20 → 152,20
.CLKOUT0_PHASE(0.0),
.CLKOUT1_PHASE(270.0),
.CLKOUT2_PHASE(0.0),
.CLKOUT3_PHASE(0.0),
.CLKOUT3_PHASE(180.0),
.CLKOUT4_PHASE(0.0),
.CLKOUT5_PHASE(180.0),
.CLKOUT5_PHASE(0.0),
.DIVCLK_DIVIDE(1), // Master division value , (1-56)
.REF_JITTER1(0.0), // Reference input jitter in UI (0.000-0.999)
.STARTUP_WAIT("FALSE") // Delayu DONE until PLL Locks, ("TRUE"/"FALSE")
.REF_JITTER1(0.0), // Ref. input jitter in UI (0.000-0.999)
.STARTUP_WAIT("TRUE") // Delay DONE until PLL Locks, ("TRUE"/"FALSE")
) genclock(
// Clock outputs: 1-bit (each) output
.CLKOUT0(i_clk),
.CLKOUT1(clk_for_ddr),
.CLKOUT2(clk2_unused), // Reserved for flash, should we need it
.CLKOUT3(enet_clk),
.CLKOUT4(clk_analyzer),
.CLKOUT5(clk_analyzer_b),
.CLKOUT2(mem_serial_clk),
.CLKOUT3(mem_serial_clk_inv),
.CLKOUT4(clk_unused),
.CLKOUT5(enet_clk),
.CLKFBOUT(clk_feedback), // 1-bit output, feedback clock
.LOCKED(clk_locked),
.CLKIN1(i_clk_100mhz),
186,11 → 187,27
wire rx_break, rx_parity_err, rx_frame_err, rx_stb;
wire tx_stb, tx_busy;
 
//
// RESET LOGIC
//
// Okay, so this looks bad at a first read--but it's not really that
// bad. If you look close, there are two parts to the reset logic.
// The first is the "PRE"-reset. This is a wire, set from the external
// reset button. In good old-fashioned asynch-logic to synchronous
// logic fashion, we synchronize this wire by registering it first
// to pre_reset, and then to pwr_reset (the actual reset wire).
//
reg pwr_reset, pre_reset;
initial pwr_reset = 1'b1;
//
// Logic description starts with the PRE-reset, so as to make certain
// we include the reset button
initial pre_reset = 1'b0;
always @(posedge i_clk)
pre_reset <= ~i_reset_btn;
//
// and then continues with the actual reset, now that we've
// synchronized our reset button wire.
initial pwr_reset = 1'b1;
always @(posedge i_clk)
pwr_reset <= pre_reset;
 
204,8 → 221,173
 
 
 
`ifdef SDRAM_ACCESS
///
///
/// The following lines are included from ddr3insert.v.
///
wire w_ddr_reset_n, w_ddr_cke, w_ddr_bus_oe;
wire [26:0] w_ddr_cmd_a, w_ddr_cmd_b;
wire [63:0] wi_ddr_data, wo_ddr_data;
wire [127:0] wide_ddr_data;
 
//
//
// Wires for setting up the DDR3 memory
//
//
 
// First, let's set up the clock(s)
xoddrserdesb ddrclk(mem_serial_clk, i_clk, pwr_reset, 8'h66,
o_ddr_ck_p, o_ddr_ck_n);
 
wire [7:0] w_udqs_in, w_ldqs_in;
 
xioddrserdesb ddrudqs(mem_serial_clk, mem_serial_clk_inv, i_clk,
~w_ddr_reset_n, w_ddr_cmd_a[0],
(w_ddr_cmd_b[0])? 8'h66 : 8'h06,
w_udqs_in,
io_ddr_dqs_p[1], io_ddr_dqs_n[1]);
 
xioddrserdesb ddrldqs(mem_serial_clk, mem_serial_clk_inv, i_clk,
~w_ddr_reset_n, w_ddr_cmd_a[0],
(w_ddr_cmd_b[0])? 8'h66 : 8'h06,
w_ldqs_in,
io_ddr_dqs_p[0], io_ddr_dqs_n[0]);
 
// The command wires: CS_N, RAS_N, CAS_N, and WE_N
xoddrserdes ddrcsn(mem_serial_clk, i_clk, ~w_ddr_reset_n,
{ w_ddr_cmd_a[26], w_ddr_cmd_a[26],
w_ddr_cmd_a[26], w_ddr_cmd_a[26],
w_ddr_cmd_b[26], w_ddr_cmd_b[26],
w_ddr_cmd_b[26], w_ddr_cmd_b[26] }, o_ddr_cs_n);
 
xoddrserdes ddrrasn(mem_serial_clk, i_clk, ~w_ddr_reset_n,
{ w_ddr_cmd_a[25], w_ddr_cmd_a[25],
w_ddr_cmd_a[25], w_ddr_cmd_a[25],
w_ddr_cmd_b[25], w_ddr_cmd_b[25],
w_ddr_cmd_b[25], w_ddr_cmd_b[25] }, o_ddr_ras_n);
 
xoddrserdes ddrcasn(mem_serial_clk, i_clk, ~w_ddr_reset_n,
{ w_ddr_cmd_a[24], w_ddr_cmd_a[24],
w_ddr_cmd_a[24], w_ddr_cmd_a[24],
w_ddr_cmd_b[24], w_ddr_cmd_b[24],
w_ddr_cmd_b[24], w_ddr_cmd_b[24] }, o_ddr_cas_n);
 
xoddrserdes ddrwen(mem_serial_clk, i_clk, ~w_ddr_reset_n,
{ w_ddr_cmd_a[23], w_ddr_cmd_a[23],
w_ddr_cmd_a[23], w_ddr_cmd_a[23],
w_ddr_cmd_b[23], w_ddr_cmd_b[23],
w_ddr_cmd_b[23], w_ddr_cmd_b[23] }, o_ddr_we_n);
 
// Data mask wires, first the upper byte
xoddrserdes ddrudm(mem_serial_clk, i_clk, ~w_ddr_reset_n,
{ w_ddr_cmd_a[4], w_ddr_cmd_a[4],
w_ddr_cmd_a[2], w_ddr_cmd_a[2],
w_ddr_cmd_b[4], w_ddr_cmd_b[4],
w_ddr_cmd_b[2], w_ddr_cmd_b[2] }, o_ddr_dm[1]);
// then the lower byte
xoddrserdes ddrldm(mem_serial_clk, i_clk, ~w_ddr_reset_n,
{ w_ddr_cmd_a[3], w_ddr_cmd_a[3],
w_ddr_cmd_a[1], w_ddr_cmd_a[1],
w_ddr_cmd_b[3], w_ddr_cmd_b[3],
w_ddr_cmd_b[1], w_ddr_cmd_b[1] }, o_ddr_dm[0]);
 
// and the On-Die termination wire
xoddrserdes ddrodt(mem_serial_clk, i_clk, ~w_ddr_reset_n,
{ w_ddr_cmd_a[0], w_ddr_cmd_a[0],
w_ddr_cmd_a[0], w_ddr_cmd_a[0],
w_ddr_cmd_b[0], w_ddr_cmd_b[0],
w_ddr_cmd_b[0], w_ddr_cmd_b[0] }, o_ddr_odt);
 
//
// Now for the data, bank, and address wires
//
genvar k;
generate begin
//
for(k=0; k<16; k=k+1)
xioddrserdes ddrdata(mem_serial_clk, mem_serial_clk_inv, i_clk, ~w_ddr_reset_n,
w_ddr_bus_oe,
{ wo_ddr_data[48+k], wo_ddr_data[48+k],
wo_ddr_data[32+k], wo_ddr_data[32+k],
wo_ddr_data[16+k], wo_ddr_data[16+k],
wo_ddr_data[ k], wo_ddr_data[ k] },
{ wide_ddr_data[112+k], wide_ddr_data[96+k],
wide_ddr_data[ 80+k], wide_ddr_data[64+k],
wide_ddr_data[ 48+k], wide_ddr_data[32+k],
wide_ddr_data[ 16+k], wide_ddr_data[ k] },
io_ddr_data[k]);
//
for(k=0; k<3; k=k+1)
xoddrserdes ddrbank(mem_serial_clk, i_clk, ~w_ddr_reset_n,
{ w_ddr_cmd_a[20+k], w_ddr_cmd_a[20+k],
w_ddr_cmd_a[20+k], w_ddr_cmd_a[20+k],
w_ddr_cmd_b[20+k], w_ddr_cmd_b[20+k],
w_ddr_cmd_b[20+k], w_ddr_cmd_b[20+k] },
o_ddr_ba[k]);
//
for(k=0; k<14; k=k+1)
xoddrserdes ddraddr(mem_serial_clk, i_clk, ~w_ddr_reset_n,
{ w_ddr_cmd_a[ 6+k], w_ddr_cmd_a[ 6+k],
w_ddr_cmd_a[ 6+k], w_ddr_cmd_a[ 6+k],
w_ddr_cmd_b[ 6+k], w_ddr_cmd_b[ 6+k],
w_ddr_cmd_b[ 6+k], w_ddr_cmd_b[ 6+k] },
o_ddr_addr[k]);
//
 
for(k=0; k<64; k=k+1)
assign wi_ddr_data[k] = (w_ddr_bus_oe) ? wide_ddr_data[2*k+1]
: wide_ddr_data[2*k];
end endgenerate
 
assign o_ddr_reset_n = w_ddr_reset_n;
assign o_ddr_cke = w_ddr_cke;
 
 
///
///
///
///
`else
wire w_ddr_reset_n, w_ddr_cke, w_ddr_bus_oe;
wire [26:0] w_ddr_cmd_a, w_ddr_cmd_b;
wire [63:0] wi_ddr_data, wo_ddr_data;
wire [127:0] wide_ddr_data;
 
//
//
// Wires for setting up the DDR3 memory
//
//
 
// Leave the SDRAM in a permanent state of reset
assign o_ddr_reset_n = 1'b0;
// Leave the SDRAM clock ... disabled
assign o_ddr_cke = 1'b0;
 
// Disable the clock(s)
OBUFDS(.I(1'b0), .O(o_ddr_ck_p), .OB(o_ddr_ck_n));
// And the data strobe
OBUFDS(.I(1'b0), .O(io_ddr_dqs_p[0]), .OB(io_ddr_dqs_n[0]));
OBUFDS(.I(1'b0), .O(io_ddr_dqs_p[1]), .OB(io_ddr_dqs_n[1]));
 
// Output ... something, anything, on the address lines
assign o_ddr_cs_n = 1'b1; // Never enable any commands
assign o_ddr_ras_n = 1'b0;
assign o_ddr_cas_n = 1'b0;
assign o_ddr_we_n = 1'b0;
assign o_ddr_ba = 3'h0;
assign o_ddr_addr = 14'h0;
assign o_ddr_dm = 2'b00;
assign o_ddr_odt = 1'b0;
 
assign io_ddr_data = 16'bzzzz_zzzz_zzzz_zzzz;
assign wi_ddr_data = io_ddr_data;
 
`endif
 
 
//////
//
//
220,14 → 402,6
wire [3:0] i_qspi_dat;
 
//
wire [31:0] wo_ddr_data, wi_ddr_data;
wire w_ddr_dqs, w_ddr_dm, w_ddr_bus_oe, w_ddr_odt;
wire [2:0] w_ddr_ba;
wire w_ddr_cs_n, w_ddr_ras_n, w_ddr_cas_n, w_ddr_we_n;
wire [13:0] w_ddr_addr;
reg [31:0] r_ddr_data;
 
//
wire w_mdio, w_mdwe;
//
wire w_sd_cmd;
243,10 → 417,8
// Quad SPI flash
w_qspi_cs_n, w_qspi_sck, qspi_dat, i_qspi_dat, qspi_bmod,
// DDR3 SDRAM
o_ddr_reset_n, o_ddr_cke,
w_ddr_cs_n, w_ddr_ras_n, w_ddr_cas_n, w_ddr_we_n,
w_ddr_dqs, w_ddr_dm, w_ddr_odt, w_ddr_bus_oe,
w_ddr_addr, w_ddr_ba, wo_ddr_data, r_ddr_data,
w_ddr_reset_n, w_ddr_cke, w_ddr_bus_oe,
w_ddr_cmd_a, w_ddr_cmd_b, wo_ddr_data, wi_ddr_data,
// SD Card
o_sd_sck, w_sd_cmd, w_sd_data, io_sd_cmd, io_sd, i_sd_cs,
// Ethernet control (MDIO) lines
330,90 → 502,8
// Wires for setting up the DDR3 memory
//
//
`ifdef SDRAM_ACCESS
reg [15:0] bottom_half_data;
always @(posedge i_clk)
bottom_half_data <= wo_ddr_data[15:0];
xioddr p0(i_clk, w_ddr_bus_oe, { wo_ddr_data[16], wo_ddr_data[0] },
{ wi_ddr_data[16], wi_ddr_data[0] }, io_ddr_data[0]);
 
xioddr p1(i_clk, w_ddr_bus_oe, { wo_ddr_data[17], wo_ddr_data[1] },
{ wi_ddr_data[17], wi_ddr_data[1] }, io_ddr_data[1]);
 
xioddr p2(i_clk, w_ddr_bus_oe, { wo_ddr_data[18], wo_ddr_data[2] },
{ wi_ddr_data[18], wi_ddr_data[2] }, io_ddr_data[2]);
 
xioddr p3(i_clk, w_ddr_bus_oe, { wo_ddr_data[19], wo_ddr_data[3] },
{ wi_ddr_data[19], wi_ddr_data[3] }, io_ddr_data[3]);
 
xioddr p4(i_clk, w_ddr_bus_oe, { wo_ddr_data[20], wo_ddr_data[4] },
{ wi_ddr_data[20], wi_ddr_data[4] }, io_ddr_data[4]);
 
xioddr p5(i_clk, w_ddr_bus_oe, { wo_ddr_data[21], wo_ddr_data[5] },
{ wi_ddr_data[21], wi_ddr_data[5] }, io_ddr_data[5]);
 
xioddr p6(i_clk, w_ddr_bus_oe, { wo_ddr_data[22], wo_ddr_data[6] },
{ wi_ddr_data[22], wi_ddr_data[6] }, io_ddr_data[6]);
 
xioddr p7(i_clk, w_ddr_bus_oe, { wo_ddr_data[23], wo_ddr_data[7] },
{ wi_ddr_data[23], wi_ddr_data[7] }, io_ddr_data[7]);
 
xioddr p8(i_clk, w_ddr_bus_oe, { wo_ddr_data[24], wo_ddr_data[8] },
{ wi_ddr_data[24], wi_ddr_data[8] }, io_ddr_data[8]);
 
xioddr p9(i_clk, w_ddr_bus_oe, { wo_ddr_data[25], wo_ddr_data[9] },
{ wi_ddr_data[25], wi_ddr_data[9] }, io_ddr_data[9]);
 
xioddr pa(i_clk, w_ddr_bus_oe, { wo_ddr_data[26], wo_ddr_data[10] },
{ wi_ddr_data[26], wi_ddr_data[10] }, io_ddr_data[10]);
 
xioddr pb(i_clk, w_ddr_bus_oe, { wo_ddr_data[27], wo_ddr_data[11] },
{ wi_ddr_data[27], wi_ddr_data[11] }, io_ddr_data[11]);
 
xioddr pc(i_clk, w_ddr_bus_oe, { wo_ddr_data[28], wo_ddr_data[12] },
{ wi_ddr_data[28], wi_ddr_data[12] }, io_ddr_data[12]);
 
xioddr pd(i_clk, w_ddr_bus_oe, { wo_ddr_data[29], wo_ddr_data[13] },
{ wi_ddr_data[29], wi_ddr_data[13] }, io_ddr_data[13]);
 
xioddr pe(i_clk, w_ddr_bus_oe, { wo_ddr_data[30], wo_ddr_data[14] },
{ wi_ddr_data[30], wi_ddr_data[14] }, io_ddr_data[14]);
 
xioddr pf(i_clk, w_ddr_bus_oe, { wo_ddr_data[31], wo_ddr_data[15] },
{ wi_ddr_data[31], wi_ddr_data[15] }, io_ddr_data[15]);
always @(posedge i_clk)
r_ddr_data <= wi_ddr_data;
 
wire [7:0] w_dqs_ignore;
xioddrds dqs0(clk_for_ddr, w_ddr_dqs, { 1'b0, 1'b1 },
{ w_dqs_ignore[0], w_dqs_ignore[1] },
io_ddr_dqs_p[0], io_ddr_dqs_n[0]);
xioddrds dqs1(clk_for_ddr, w_ddr_dqs, { 1'b0, 1'b1 },
{ w_dqs_ignore[2], w_dqs_ignore[3] },
io_ddr_dqs_p[1], io_ddr_dqs_n[1]);
 
xoddr xcs_n( i_clk, { w_ddr_cs_n, w_ddr_cs_n }, o_ddr_cs_n);
xoddr xras_n(i_clk, { w_ddr_ras_n, w_ddr_ras_n }, o_ddr_ras_n);
xoddr xcas_n(i_clk, { w_ddr_cas_n, w_ddr_cas_n }, o_ddr_cas_n);
xoddr xwe_n( i_clk, { w_ddr_we_n, w_ddr_we_n }, o_ddr_we_n);
xoddr xba0( i_clk, { w_ddr_ba[0], w_ddr_ba[0] }, o_ddr_ba[0]);
xoddr xba1( i_clk, { w_ddr_ba[1], w_ddr_ba[1] }, o_ddr_ba[1]);
xoddr xba2( i_clk, { w_ddr_ba[2], w_ddr_ba[2] }, o_ddr_ba[2]);
xoddr xaddr0(i_clk, { w_ddr_addr[0], w_ddr_addr[0] }, o_ddr_addr[0]);
xoddr xaddr1(i_clk, { w_ddr_addr[1], w_ddr_addr[1] }, o_ddr_addr[1]);
xoddr xaddr2(i_clk, { w_ddr_addr[2], w_ddr_addr[2] }, o_ddr_addr[2]);
xoddr xaddr3(i_clk, { w_ddr_addr[3], w_ddr_addr[3] }, o_ddr_addr[3]);
xoddr xaddr4(i_clk, { w_ddr_addr[4], w_ddr_addr[4] }, o_ddr_addr[4]);
xoddr xaddr5(i_clk, { w_ddr_addr[5], w_ddr_addr[5] }, o_ddr_addr[5]);
xoddr xaddr6(i_clk, { w_ddr_addr[6], w_ddr_addr[6] }, o_ddr_addr[6]);
xoddr xaddr7(i_clk, { w_ddr_addr[7], w_ddr_addr[7] }, o_ddr_addr[7]);
xoddr xaddr8(i_clk, { w_ddr_addr[8], w_ddr_addr[8] }, o_ddr_addr[8]);
xoddr xaddr9(i_clk, { w_ddr_addr[9], w_ddr_addr[9] }, o_ddr_addr[9]);
xoddr xaddr10(i_clk,{ w_ddr_addr[10],w_ddr_addr[10]}, o_ddr_addr[10]);
xoddr xaddr11(i_clk,{ w_ddr_addr[11],w_ddr_addr[11]}, o_ddr_addr[11]);
xoddr xaddr12(i_clk,{ w_ddr_addr[12],w_ddr_addr[12]}, o_ddr_addr[12]);
xoddr xaddr13(i_clk,{ w_ddr_addr[13],w_ddr_addr[13]}, o_ddr_addr[13]);
 
/*
wire w_clk_for_ddr;
ODDR #(.DDR_CLK_EDGE("SAME_EDGE"))
memclkddr(.Q(w_clk_for_ddr), .C(clk_for_ddr), .CE(1'b1),
420,52 → 510,7
.D1(1'b0), .D2(1'b1), .R(1'b0), .S(1'b0));
OBUFDS #(.IOSTANDARD("DIFF_SSTL135"), .SLEW("FAST"))
clkbuf(.O(o_ddr_ck_p), .OB(o_ddr_ck_n), .I(w_clk_for_ddr));
*/
 
// assign o_ddr_dm[0] = w_ddr_dm;
// assign o_ddr_dm[1] = w_ddr_dm;
xoddr xdm0(i_clk,{ w_ddr_dm, w_ddr_dm }, o_ddr_dm[0]);
xoddr xdm1(i_clk,{ w_ddr_dm, w_ddr_dm }, o_ddr_dm[1]);
 
assign o_ddr_odt = (~o_ddr_reset_n)? 1'bz : w_ddr_odt;
 
// xlogicanalyzer ladata(i_clk, io_ddr_data[0], w_ddr_debug[3:0]);
// xlogicanalyzer ladclk(clk_analyzer, clk_analyzer_b,
// i_clk, o_ddr_ck_p, w_ddr_debug[7:4]);
assign w_ddr_debug[7:4] = 4'h0;
assign w_ddr_debug[3:0] = 4'h0;
`else
assign o_ddr_cs_n = w_ddr_cs_n;
assign o_ddr_ras_n = w_ddr_ras_n;
assign o_ddr_cas_n = w_ddr_cas_n;
assign o_ddr_we_n = w_ddr_we_n;
//
assign o_ddr_ba = w_ddr_ba;
assign o_ddr_addr = w_ddr_addr;
//
assign o_ddr_dm[1:0] = 2'b00;
assign o_ddr_odt = 1'b0;
//
assign io_ddr_data = 16'bzzzz_zzzz_zzzz_zzzz;
always @(posedge i_clk)
r_ddr_data = 16'h0000;
 
//wire w_clk_for_ddr;
//ODDR #(.DDR_CLK_EDGE("SAME_EDGE"))
//memclkddr(.Q(w_clk_for_ddr), .C(clk_for_ddr), .CE(1'b1),
//.D1(1'b0), .D2(1'b1), .R(1'b0), .S(1'b0));
OBUFDS #(.IOSTANDARD("DIFF_SSTL135"), .SLEW("FAST"))
clkbuf(.O(o_ddr_ck_p), .OB(o_ddr_ck_n), .I(1'b1));
 
wire [7:0] w_dqs_ignore;
xioddrds dqs0(clk_for_ddr, w_ddr_dqs, { 1'b0, 1'b1 },
{ w_dqs_ignore[0], w_dqs_ignore[1] },
io_ddr_dqs_p[0], io_ddr_dqs_n[0]);
xioddrds dqs1(clk_for_ddr, w_ddr_dqs, { 1'b0, 1'b1 },
{ w_dqs_ignore[2], w_dqs_ignore[3] },
io_ddr_dqs_p[1], io_ddr_dqs_n[1]);
 
 
`endif
 
endmodule
 
/xioddrds.v
0,0 → 1,85
////////////////////////////////////////////////////////////////////////////////
//
// Filename: xioddrds.v
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose: For the DDR3 SDRAM, this handles the Xilinx specific portions
// of the IO necessary to make this happen for differential I/O
// pins.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
module xioddrds(i_clk, i_oe, i_v, o_v, io_p, io_n);
input i_clk, i_oe;
input [1:0] i_v;
output [1:0] o_v;
inout io_p, io_n;
 
wire w_internal, w_read_path;
 
ODDR #(
.DDR_CLK_EDGE("SAME_EDGE"),
.INIT(1'b0),
.SRTYPE("SYNC")
) ODDRi(
.Q(w_internal),
.C(i_clk),
.CE(1'b1),
.D1(i_v[0]),
.D2(i_v[1]),
.R(1'b0),
.S(1'b0));
 
IDDR #(
.DDR_CLK_EDGE("SAME_EDGE_PIPELINED"),
.INIT_Q1(1'b0),
.INIT_Q2(1'b0),
.SRTYPE("SYNC")
) IDDRi(
.Q1(o_v[0]),
.Q2(o_v[1]),
.C(i_clk),
.CE(1'b1),
.D(w_read_path),
.R(1'b0),
.S(1'b0));
 
IOBUFDS #(
.DIFF_TERM("FALSE"),
.IBUF_LOW_PWR("TRUE"),
.IOSTANDARD("DIFF_SSTL135"),
.SLEW("FAST")
) IOBUFDSi(
.O(w_read_path),
.IO(io_p),.IOB(io_n),
.I(w_internal),
.T(i_oe));
endmodule
/ddr3insert.v
0,0 → 1,198
////////////////////////////////////////////////////////////////////////////////
//
// Filename: ddr3insert.v
//
// Project: A wishbone controlled DDR3 SDRAM memory controller.
//
// Purpose: Since the DDR3 RAM requires I/O resources not available
// in Verilog alone, this insert (i.e. include file) is designed
// to be included from a top-level block that would otherwise use the
// DDR3 SDRAM. It is meant to encapsulate the I/O resource requirements
// and connections required to make the DDR3 SDRAM work.
//
//
// This file is not a module in its own right, but rather a file
// included in a larger module.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
 
// EXTERNAL PINS (BOTH INPUT AND OUTPUT):
// o_ddr_reset_n, o_ddr_cke, o_ddr_ck_p, o_ddr_ck_n
// o_ddr_cs_n, o_ddr_ras_n, o_ddr_cas_n, o_ddr_we_n,
// io_ddr_dqs_p, io_ddr_dqs_n,
// o_ddr_addr, o_ddr_ba,
// io_ddr_data, o_ddr_dm, o_ddr_odt
//
// INPUTS: (from elsewhere in the toplevel module)
// pwr_reset True for one clock at power on
// i_clk 200 MHz clock used in fabric
// clk_for_ddr 800 MHz clock to send to memory clk pins
// mem_serial_clk 800 MHz clock to drive serdes's
// mem_serial_clk_inv The inverse of the 800 MHz clock ...
//
//
// LOCAL VARIABLES PROVIDED:
// (These come from the controller)
// [3:0] w_ddr_cs_n, w_ddr_ras_n, w_ddr_cas_n, w_ddr_we_n
// [11:0] w_ddr_ba, divided into
// { w_ddr_ba[11:9], w_ddr_ba[8:6], w_ddr[5:3], w_ddr_ba[2:0] }
// [55:0] w_ddr_addr
// { w_ddr_addr[55:42], w_ddr_addr[41:28], w_ddr_addr[27:14],
// w_ddr_addr[13:0] }
// [7:0] w_ddr_odt // On-die termination
// [7:0] w_ddr_odt // On-die termination
// [15:0] w_ddr_dm // Data mask, headed to memory
// [127:0] wo_ddr_data // Data going to the memory
// [127:0] wi_ddr_data // The data returned by the memory
//
//
 
//
wire w_ddr_reset_n, w_ddr_cke, w_ddr_bus_oe;
wire [26:0] w_ddr_cmd_a, w_ddr_cmd_b;
wire [63:0] wi_ddr_data, wo_ddr_data;
wire [127:0] wide_ddr_data;
 
//
//
// Wires for setting up the DDR3 memory
//
//
 
// First, let's set up the clock(s)
xoddrserdesb ddrclk(mem_serial_clk, i_clk, pwr_reset, 8'h66,
o_ddr_ck_p, o_ddr_ck_n);
 
wire [7:0] w_udqs_in, w_ldqs_in;
 
xioddrserdesb ddrudqs(mem_serial_clk, mem_serial_clk_inv, i_clk,
~w_ddr_reset_n, w_ddr_cmd_a[0],
(w_ddr_cmd_b[0])? 8'h66 : 8'h06,
w_udqs_in,
io_ddr_dqs_p[1], io_ddr_dqs_n[1]);
 
xioddrserdesb ddrldqs(mem_serial_clk, mem_serial_clk_inv, i_clk,
~w_ddr_reset_n, w_ddr_cmd_a[0],
(w_ddr_cmd_b[0])? 8'h66 : 8'h06,
w_ldqs_in,
io_ddr_dqs_p[0], io_ddr_dqs_n[0]);
 
// The command wires: CS_N, RAS_N, CAS_N, and WE_N
xoddrserdes ddrcsn(mem_serial_clk, i_clk, ~w_ddr_reset_n,
{ w_ddr_cmd_a[26], w_ddr_cmd_a[26],
w_ddr_cmd_a[26], w_ddr_cmd_a[26],
w_ddr_cmd_b[26], w_ddr_cmd_b[26],
w_ddr_cmd_b[26], w_ddr_cmd_b[26] }, o_ddr_cs_n);
 
xoddrserdes ddrrasn(mem_serial_clk, i_clk, ~w_ddr_reset_n,
{ w_ddr_cmd_a[25], w_ddr_cmd_a[25],
w_ddr_cmd_a[25], w_ddr_cmd_a[25],
w_ddr_cmd_b[25], w_ddr_cmd_b[25],
w_ddr_cmd_b[25], w_ddr_cmd_b[25] }, o_ddr_ras_n);
 
xoddrserdes ddrcasn(mem_serial_clk, i_clk, ~w_ddr_reset_n,
{ w_ddr_cmd_a[24], w_ddr_cmd_a[24],
w_ddr_cmd_a[24], w_ddr_cmd_a[24],
w_ddr_cmd_b[24], w_ddr_cmd_b[24],
w_ddr_cmd_b[24], w_ddr_cmd_b[24] }, o_ddr_cas_n);
 
xoddrserdes ddrwen(mem_serial_clk, i_clk, ~w_ddr_reset_n,
{ w_ddr_cmd_a[23], w_ddr_cmd_a[23],
w_ddr_cmd_a[23], w_ddr_cmd_a[23],
w_ddr_cmd_b[23], w_ddr_cmd_b[23],
w_ddr_cmd_b[23], w_ddr_cmd_b[23] }, o_ddr_we_n);
 
// Data mask wires, first the upper byte
xoddrserdes ddrudm(mem_serial_clk, i_clk, ~w_ddr_reset_n,
{ w_ddr_cmd_a[4], w_ddr_cmd_a[4],
w_ddr_cmd_a[2], w_ddr_cmd_a[2],
w_ddr_cmd_b[4], w_ddr_cmd_b[4],
w_ddr_cmd_b[2], w_ddr_cmd_b[2] }, o_ddr_dm[1]);
// then the lower byte
xoddrserdes ddrldm(mem_serial_clk, i_clk, ~w_ddr_reset_n,
{ w_ddr_cmd_a[3], w_ddr_cmd_a[3],
w_ddr_cmd_a[1], w_ddr_cmd_a[1],
w_ddr_cmd_b[3], w_ddr_cmd_b[3],
w_ddr_cmd_b[1], w_ddr_cmd_b[1] }, o_ddr_dm[0]);
 
// and the On-Die termination wire
xoddrserdes ddrodt(mem_serial_clk, i_clk, ~w_ddr_reset_n,
{ w_ddr_cmd_a[0], w_ddr_cmd_a[0],
w_ddr_cmd_a[0], w_ddr_cmd_a[0],
w_ddr_cmd_b[0], w_ddr_cmd_b[0],
w_ddr_cmd_b[0], w_ddr_cmd_b[0] }, o_ddr_odt);
 
//
// Now for the data, bank, and address wires
//
genvar k;
generate begin
//
for(k=0; k<16; k=k+1)
xioddrserdes ddrdata(mem_serial_clk, mem_serial_clk_inv, i_clk, ~w_ddr_reset_n,
w_ddr_bus_oe,
{ wo_ddr_data[48+k], wo_ddr_data[48+k],
wo_ddr_data[32+k], wo_ddr_data[32+k],
wo_ddr_data[16+k], wo_ddr_data[16+k],
wo_ddr_data[ k], wo_ddr_data[ k] },
{ wide_ddr_data[112+k], wide_ddr_data[96+k],
wide_ddr_data[ 80+k], wide_ddr_data[64+k],
wide_ddr_data[ 48+k], wide_ddr_data[32+k],
wide_ddr_data[ 16+k], wide_ddr_data[ k] },
io_ddr_data[k]);
//
for(k=0; k<3; k=k+1)
xoddrserdes ddrbank(mem_serial_clk, i_clk, ~w_ddr_reset_n,
{ w_ddr_cmd_a[20+k], w_ddr_cmd_a[20+k],
w_ddr_cmd_a[20+k], w_ddr_cmd_a[20+k],
w_ddr_cmd_b[20+k], w_ddr_cmd_b[20+k],
w_ddr_cmd_b[20+k], w_ddr_cmd_b[20+k] },
o_ddr_ba[k]);
//
for(k=0; k<14; k=k+1)
xoddrserdes ddraddr(mem_serial_clk, i_clk, ~w_ddr_reset_n,
{ w_ddr_cmd_a[ 6+k], w_ddr_cmd_a[ 6+k],
w_ddr_cmd_a[ 6+k], w_ddr_cmd_a[ 6+k],
w_ddr_cmd_b[ 6+k], w_ddr_cmd_b[ 6+k],
w_ddr_cmd_b[ 6+k], w_ddr_cmd_b[ 6+k] },
o_ddr_addr[k]);
//
 
for(k=0; k<64; k=k+1)
assign wi_ddr_data[k] = (w_ddr_bus_oe) ? wide_ddr_data[2*k+1]
: wide_ddr_data[2*k];
end endgenerate
 
assign o_ddr_reset_n = w_ddr_reset_n;
assign o_ddr_cke = w_ddr_cke;
 
 
/xoddrserdes.v
0,0 → 1,94
////////////////////////////////////////////////////////////////////////////////
//
// Filename: xoddrserdes.v
//
// Project: A wishbone controlled DDR3 SDRAM memory controller.
//
// Purpose: Provide DDR outputs at 8x the clock rate (with a 4x clock given)
// for such things as the memory clock output, and the data strobe
// output (DQS) which needs to be synchronous with the memory clock output.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
module xoddrserdes(i_clk_fast, i_clk_slow, i_reset, i_data, o_pin);
input i_clk_fast, i_clk_slow, i_reset;
input [7:0] i_data;
output o_pin;
 
wire local_monitor_pin__unconnected;
wire oe_for_fabric__unconnected;
wire [1:0] local_shiftout__unconnected;
wire local_tbyte_out__unconnected;
wire send_to_iob;
wire oe_for_iob;
 
OSERDESE2 #(
.DATA_RATE_OQ("DDR"),
.DATA_RATE_TQ("BUF"),
.DATA_WIDTH(8), // 8 data wires sent per clkdiv
.INIT_OQ(1'b1),
.SERDES_MODE("MASTER"),
//
.TRISTATE_WIDTH(1),
.INIT_TQ(1'b1),
.TBYTE_CTL("FALSE"),
.TBYTE_SRC("FALSE")
) oserdes_i(
.CLK(i_clk_fast),
.CLKDIV(i_clk_slow),
.OCE(1'b1),
.OFB(local_monitor_pin__unconnected),
.OQ(send_to_iob),
.RST(i_reset),
//
.TCE(1'b1),
.TQ(oe_for_iob),
.TFB(oe_for_fabric__unconnected),
.T1(1'b0), .T2(1'b0), .T3(1'b0), .T4(1'b0),
//
.SHIFTOUT1(local_shiftout__unconnected[0]),
.SHIFTOUT2(local_shiftout__unconnected[1]),
.SHIFTIN1(1'b0),
.SHIFTIN2(1'b0),
.TBYTEIN(1'b0),
.TBYTEOUT(local_tbyte_out__unconnected),
//
// And now for the actual data we wish to send
//
.D1(i_data[0]), .D2(i_data[1]),
.D3(i_data[2]), .D4(i_data[3]),
.D5(i_data[4]), .D6(i_data[5]),
.D7(i_data[6]), .D8(i_data[7])
);
 
OBUF iobuf_i(.I(send_to_iob), .O(o_pin));
 
endmodule
 
/xoddrserdesb.v
0,0 → 1,97
////////////////////////////////////////////////////////////////////////////////
//
// Filename: xoddrserdes.v
//
// Project: A wishbone controlled DDR3 SDRAM memory controller.
//
// Purpose: Provide DDR outputs at 8x the clock rate (with a 4x clock given)
// for such things as the memory clock output, and the data strobe
// output (DQS) which needs to be synchronous with the memory clock output.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
module xoddrserdesb(i_clk_fast, i_clk_slow, i_reset,
i_data, o_pin_p, o_pin_n);
input i_clk_fast, i_clk_slow, i_reset;
input [7:0] i_data;
output wire o_pin_p, o_pin_n;
 
wire local_monitor_pin__unconnected;
wire oe_for_fabric__unconnected;
wire [1:0] local_shiftout__unconnected;
wire local_tbyte_out__unconnected;
wire send_to_iob;
wire oe_for_iob;
 
OSERDESE2 #(
.DATA_RATE_OQ("DDR"),
.DATA_RATE_TQ("BUF"),
.DATA_WIDTH(8), // 8 data wires sent per clkdiv
.INIT_OQ(1'b1),
.SERDES_MODE("MASTER"),
//
.TRISTATE_WIDTH(1),
.INIT_TQ(1'b1),
.TBYTE_CTL("FALSE"),
.TBYTE_SRC("FALSE")
) oserdes_i(
.CLK(i_clk_fast),
.CLKDIV(i_clk_slow),
.OCE(1'b1),
.OFB(local_monitor_pin__unconnected),
.OQ(send_to_iob),
.RST(i_reset),
//
.TCE(1'b1),
.TQ(oe_for_iob),
.TFB(oe_for_fabric__unconnected),
.T1(1'b0), .T2(1'b0), .T3(1'b0), .T4(1'b0),
//
.SHIFTOUT1(local_shiftout__unconnected[0]),
.SHIFTOUT2(local_shiftout__unconnected[1]),
.SHIFTIN1(1'b0),
.SHIFTIN2(1'b0),
.TBYTEIN(1'b0),
.TBYTEOUT(local_tbyte_out__unconnected),
//
// And now for the actual data we wish to send
//
.D1(i_data[0]), .D2(i_data[1]),
.D3(i_data[2]), .D4(i_data[3]),
.D5(i_data[4]), .D6(i_data[5]),
.D7(i_data[6]), .D8(i_data[7])
);
 
OBUFDS iobuf_i(
.I(send_to_iob),
.O(o_pin_p), .OB(o_pin_n));
 
endmodule
 
/xioddrserdesb.v
0,0 → 1,134
////////////////////////////////////////////////////////////////////////////////
//
// Filename: xioddrserdesb.v
//
// Project: A wishbone controlled DDR3 SDRAM memory controller.
//
// Purpose:
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
module xioddrserdesb(i_clk_fast, i_clk_fast_inv, i_clk_slow, i_reset,
i_oe, i_data, o_data, io_pin_p, io_pin_n);
input i_clk_fast, i_clk_fast_inv, i_clk_slow, i_reset;
input i_oe;
input [7:0] i_data;
output [7:0] o_data;
inout io_pin_p, io_pin_n;
 
wire feedback;
wire oe_for_fabric__unconnected;
wire [1:0] local_shiftout__unconnected;
wire local_tbyte_out__unconnected;
wire send_to_iob;
wire oe_for_iob;
wire [1:0] iserdes_shiftout__unconnected;
 
OSERDESE2 #(
.DATA_RATE_OQ("DDR"),
.DATA_RATE_TQ("BUF"),
.DATA_WIDTH(8), // 8 data wires sent per clkdiv
.INIT_OQ(1'b1),
.SERDES_MODE("MASTER"),
//
.TRISTATE_WIDTH(1),
.INIT_TQ(1'b1),
.TBYTE_CTL("FALSE"),
.TBYTE_SRC("FALSE")
) oserdes_i(
.CLK(i_clk_fast),
.CLKDIV(i_clk_slow),
.OCE(1'b1),
.OFB(feedback),
.OQ(send_to_iob),
.RST(i_reset),
//
.TCE(1'b1),
.TQ(oe_for_iob),
.TFB(oe_for_fabric__unconnected),
.T1(~i_oe), .T2(~i_oe), .T3(~i_oe), .T4(~i_oe),
//
.SHIFTOUT1(local_shiftout__unconnected[0]),
.SHIFTOUT2(local_shiftout__unconnected[1]),
.SHIFTIN1(1'b0),
.SHIFTIN2(1'b0),
.TBYTEIN(1'b0),
.TBYTEOUT(local_tbyte_out__unconnected),
//
// And now for the actual data we wish to send
//
.D1(i_data[0]), .D2(i_data[1]),
.D3(i_data[2]), .D4(i_data[3]),
.D5(i_data[4]), .D6(i_data[5]),
.D7(i_data[6]), .D8(i_data[7])
);
 
IOBUFDS iobuf_i(
.T(oe_for_iob),
.I(send_to_iob),
.IO(io_pin_p), .IOB(io_pin_n),
.O(input_from_iobuf));
 
ISERDESE2 #(
.DATA_RATE("DDR"),
.DATA_WIDTH(8), // 8 data wires sent per clkdiv
.INTERFACE_TYPE("OVERSAMPLE"),
.IOBDELAY("NONE"),
.NUM_CE(1),
.OFB_USED("FALSE"),
.SERDES_MODE("MASTER")
) iserdes_i(
.BITSLIP(1'b0),
.CE1(1'b1),
.CE2(1'b1),
.CLK(i_clk_fast),
.CLKB(i_clk_fast_inv),
.CLKDIV(i_clk_slow),
.CLKDIVP(1'b0), // Only used in MEMORY_DDR3 mode?
.D(input_from_iobuf),
.DDLY(1'b0),
.DYNCLKDIVSEL(1'b0),
.DYNCLKSEL(1'b0),
.O(iserdes_unconnected_output),
.OCLK(i_clk_fast),
.OCLKB(i_clk_fast_inv),
.OFB(feedback),
.Q1(o_data[0]), .Q2(o_data[1]),
.Q3(o_data[2]), .Q4(o_data[3]),
.Q5(o_data[4]), .Q6(o_data[5]),
.Q7(o_data[6]), .Q8(o_data[7]),
.RST(i_reset),
.SHIFTIN1(1'b0), .SHIFTIN2(1'b0),
.SHIFTOUT1(iserdes_shiftout__unconnected[0]),
.SHIFTOUT2(iserdes_shiftout__unconnected[1])
);
 
endmodule
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.