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

Subversion Repositories wbddr3

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /wbddr3/trunk
    from Rev 15 to Rev 16
    Reverse comparison

Rev 15 → Rev 16

/bench/cpp/ddrsdramsim.h
49,6 → 49,7
 
#define NBANKS 8
#define NTIMESLOTS 32
#define NWIDTH 2
 
class BANKINFO {
public:
75,11 → 76,19
public:
BANKINFO m_bank[8];
DDRSDRAMSIM(int lglen);
unsigned operator()(int, int,
unsigned apply(int, int,
int, int, int, int,
int, int, int, int,
int, int, int);
unsigned &operator[](unsigned addr) { return m_mem[addr]; };
unsigned operator()(int reset_n, int cke,
int csn, int rasn, int casn, int wen,
int dqs, int dm, int odt, int busoe,
int addr, int ba, int data) {
return apply(reset_n, cke, csn, rasn, casn, wen, dqs, dm, odt,
busoe, addr, ba, data);
}
unsigned &mem(unsigned addr) { return m_mem[addr]; };
unsigned &operator[](unsigned addr) { return mem(addr); };
};
 
#endif
/bench/cpp/pddrsim.cpp
0,0 → 1,87
////////////////////////////////////////////////////////////////////////////////
//
// Filename: pddrsim.cpp
//
// Project: A wishbone controlled DDR3 SDRAM memory controller.
//
// Purpose: To expand a DDR3 SDRAM controllers influence across multiple
// clocks. Hence, if the DDR3 SDRAM controller runs at half
// the clock rate of the DDR3-SDRAM, this will expand it to the full
// clock rate.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 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
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
#include <stdio.h>
#include <stdlib.h>
#include "ddrsdramsim.h"
#include "pddrsim.h"
 
unsigned long PDDRSIM::operator()(int reset_n, int cke, int busoe,
unsigned cmda, unsigned cmdb, unsigned long data) {
int csn, rasn, casn, wen, dqs, dm, odt, addr, ba;
unsigned hdata, ldata;
unsigned long odata;
 
// if ((reset_n)&&(cke)) printf("PDDR: %08x/%08x/%016lx\n", cmda, cmdb, data);
csn = (cmda >> 26)&1;
rasn = (cmda >> 25)&1;
casn = (cmda >> 24)&1;
wen = (cmda >> 23)&1;
ba = (cmda >> 20)&0x7; // 3 bits
addr = (cmda >> 6)&0x3fff; // 14 bits
dqs = (cmda >> 5)&0x01; // 1 bits
dm = (cmda >> 1)&0x0f; // 4 bits
odt = (cmda )&0x01; // 1 bits
 
// if ((reset_n)&&(cke)) printf("PDDR: %s/%02x/%s\n", (dqs)?"DQS":" ",dm,(odt)?"ODT":" ");
 
hdata = DDRSDRAMSIM::apply(reset_n, cke, csn, rasn, casn, wen,
dqs, dm, odt, busoe, addr, ba, (unsigned)(data>>32));
 
csn = (cmdb >> 26)&1;
rasn = (cmdb >> 25)&1;
casn = (cmdb >> 24)&1;
wen = (cmdb >> 23)&1;
ba = (cmdb >> 20)&0x7; // 3 bits
addr = (cmdb >> 6)&0x3fff; // 14 bits
dqs = (cmdb >> 5)&0x01; // 1 bits
dm = (cmdb >> 1)&0x0f; // 4 bits
odt = (cmdb )&0x01; // 1 bits
 
// if ((reset_n)&&(cke)) printf("PDDR: %s/%02x/%s\n", (dqs)?"DQS":" ",dm,(odt)?"ODT":" ");
 
ldata = DDRSDRAMSIM::apply(reset_n, cke, csn, rasn, casn, wen,
dqs, dm, odt, busoe, addr, ba, (unsigned)(data&(~(-1l<<32))));
 
 
odata = (((unsigned long)hdata)<<32)|((unsigned long)ldata);
return odata;
}
 
/bench/cpp/ddrsdram_tb.cpp
41,7 → 41,8
 
#include "verilated.h"
#include "Vwbddrsdram.h"
#include "ddrsdramsim.h"
#include "pddrsim.h"
// #include "ddrsdramsim.h"
 
const int BOMBCOUNT = 2048,
SDRAMMASK = 0x3ffffff,
50,18 → 51,18
class DDRSDRAM_TB {
long m_tickcount;
Vwbddrsdram *m_core;
DDRSDRAMSIM *m_sdram;
PDDRSIM *m_sdram;
bool m_bomb;
public:
 
DDRSDRAM_TB(void) {
m_core = new Vwbddrsdram;
m_sdram= new DDRSDRAMSIM(LGMEMSIZE);
m_sdram= new PDDRSIM(LGMEMSIZE);
}
 
unsigned &operator[](const int index) { return (*m_sdram)[index]; }
void set(unsigned addr, unsigned v) {
(*m_sdram)[addr] = v;
unsigned long operator[](const int index) { return (*m_sdram)[index]; }
void set(unsigned addr, unsigned long v) {
m_sdram->set(addr, v);
}
 
void tick(void) {
70,32 → 71,36
m_core->i_ddr_data = (*m_sdram)(
m_core->o_ddr_reset_n,
m_core->o_ddr_cke,
m_core->o_ddr_cs_n,
m_core->o_ddr_ras_n,
m_core->o_ddr_cas_n,
m_core->o_ddr_we_n,
m_core->o_ddr_dqs,
m_core->o_ddr_dm,
m_core->o_ddr_odt,
m_core->o_ddr_bus_oe,
m_core->o_ddr_addr,
m_core->o_ddr_ba,
m_core->o_ddr_cmd_a,
m_core->o_ddr_cmd_b,
m_core->o_ddr_data);
 
bool writeout = (!m_core->v__DOT__reset_override);
 
int cmd;
cmd = (m_core->o_ddr_reset_n?0:32)
int cmda, cmdb, cmd;
cmda = (m_core->o_ddr_reset_n?0:32)
|(m_core->o_ddr_cke?0:16)
|(m_core->o_ddr_cs_n?8:0)
|(m_core->o_ddr_ras_n?4:0)
|(m_core->o_ddr_cas_n?2:0)
|(m_core->o_ddr_we_n?1:0);
if ((cmd&0x0f)==DDR_REFRESH)
|((m_core->o_ddr_cmd_a&(1<<26))?8:0)
|((m_core->o_ddr_cmd_a&(1<<25))?4:0)
|((m_core->o_ddr_cmd_a&(1<<24))?2:0)
|((m_core->o_ddr_cmd_a&(1<<23))?1:0);
cmdb = (m_core->o_ddr_reset_n?0:32)
|(m_core->o_ddr_cke?0:16)
|((m_core->o_ddr_cmd_b&(1<<26))?8:0)
|((m_core->o_ddr_cmd_b&(1<<25))?4:0)
|((m_core->o_ddr_cmd_b&(1<<24))?2:0)
|((m_core->o_ddr_cmd_b&(1<<23))?1:0);
cmd = m_core->o_ddr_cmd_b;
if ((cmdb&0x0f)!=DDR_NOOP)
cmd = m_core->o_ddr_cmd_a;
if ((cmda&0x0f)==DDR_REFRESH)
writeout = true;
if ((cmdb&0x0f)==DDR_REFRESH)
writeout = true;
 
if (writeout) {
printf("%08lx-WB: %s/%s %s%s%s %s@0x%08x[%08x/%08x] -- ",
printf("%08lx-WB: %s/%s %s%s%s %s@0x%08x[%016lx/%016lx] -- ",
m_tickcount,
(m_core->i_wb_cyc)?"CYC":" ",
(m_core->i_wb_stb)?"STB":" ",
107,25 → 112,28
(m_core->i_wb_data),
(m_core->o_wb_data));
 
printf("%s%s %d%d%d%d %s%s%s%s B[%d]@%04x %08x %08x",
printf("%s%s %d%d%d%d,%d%d%d%d %s%s[%x%x]%s%s B[%d,%d]@%04x %016lx %016lx",
(m_core->o_ddr_reset_n)?" ":"R",
(m_core->o_ddr_cke)?"CK":" ",
(m_core->o_ddr_cs_n),
(m_core->o_ddr_ras_n),
(m_core->o_ddr_cas_n),
(m_core->o_ddr_we_n),
(cmda&0x08)?1:0, (cmda&0x04)?1:0,
(cmda&0x02)?1:0, (cmda&0x01)?1:0,
(cmdb&0x08)?1:0, (cmdb&0x04)?1:0,
(cmdb&0x02)?1:0, (cmdb&0x01)?1:0,
//
(m_core->o_ddr_dqs)?"D":" ",
(m_core->o_ddr_dm)?"M":" ",
(m_core->o_ddr_odt)?"O":" ",
((m_core->o_ddr_cmd_a>>5)&1)?"D":"-",
((m_core->o_ddr_cmd_b>>5)&1)?"D":"-",
((m_core->o_ddr_cmd_a>>1)&0x0f),
((m_core->o_ddr_cmd_b>>1)&0x0f),
(m_core->o_ddr_cmd_a&1)?"O":" ",
(m_core->o_ddr_bus_oe)?"E":" ",
//
(m_core->o_ddr_ba),
(m_core->o_ddr_addr),
(m_core->o_ddr_cmd_a>>(6+14))&0x07, // Get the bank address
(m_core->o_ddr_cmd_b>>(6+14))&0x07, // Get the bank address
((cmd>>6)&0x03fff), // The command address
(m_core->i_ddr_data),
(m_core->o_ddr_data));
 
printf(" FIFO[%x,%x](%s,%d,%08x)",
printf(" FIFO[%x,%x](%s,%d,%016lx)",
m_core->v__DOT__bus_fifo_head,
m_core->v__DOT__bus_fifo_tail,
(m_core->v__DOT__bus_fifo_new[m_core->v__DOT__bus_fifo_tail])?"N":"o",
132,16 → 140,17
m_core->v__DOT__bus_fifo_sub[m_core->v__DOT__bus_fifo_tail],
m_core->v__DOT__bus_fifo_data[m_core->v__DOT__bus_fifo_tail]);
 
printf(" BUS[A%03x/R%03x/N%03x/K%03x/%d]",
printf(" BUS[A%03x/R%03x/N%03x/K%03x/T%03x/%02x]",
(m_core->v__DOT__bus_active),
(m_core->v__DOT__bus_read),
(m_core->v__DOT__bus_new),
(m_core->v__DOT__bus_ack),
(m_core->v__DOT__bus_subaddr[8]));
(m_core->v__DOT__bus_odt),
(m_core->v__DOT__bus_subaddr));
 
/*
// Reset logic
printf(" RST(%06x%s[%d] - %08x->%08x)",
printf(" RST(%06x%s[%2d] - %08x->%08x)",
m_core->v__DOT__reset_timer,
(m_core->v__DOT__reset_ztimer)?"Z":" ",
(m_core->v__DOT__reset_address),
149,7 → 158,7
(m_core->v__DOT__reset_cmd));
*/
 
printf(" R_%s%03x[%d]%04x:%d/%08x",
printf(" R_%s%03x[%d]%04x:%d/%02x/%016lx",
(!m_core->v__DOT__r_pending)?"_"
:(m_core->v__DOT__r_we)?"W":"R",
(m_core->v__DOT__r_row),
156,9 → 165,10
(m_core->v__DOT__r_bank),
(m_core->v__DOT__r_col),
(m_core->v__DOT__r_sub),
(m_core->v__DOT__r_sel),
(m_core->v__DOT__r_data));
 
printf(" S_%s%03x[%d]%04x:%d/%08x%s%s%s",
printf(" S_%s%03x[%d]%04x:%d/%02x/%016lx%s%s%s",
(!m_core->v__DOT__s_pending)?"_"
:(m_core->v__DOT__s_we)?"W":"R",
(m_core->v__DOT__s_row),
165,6 → 175,7
(m_core->v__DOT__s_bank),
(m_core->v__DOT__s_col),
(m_core->v__DOT__s_sub),
(m_core->v__DOT__s_sel),
(m_core->v__DOT__s_data),
(m_core->v__DOT__w_s_match)?"M":" ",
(m_core->v__DOT__pipe_stall)?"P":" ",
180,13 → 191,14
//:(m_core->v__DOT__maybe_close_next_bank)?"c":"N",
(m_core->v__DOT__need_open_bank)?"O":"K");
// :(m_core->v__DOT__maybe_open_next_bank)?"o":"K");
 
for(int i=0; i<8; i++) {
printf("%s%s%s%x%x@%x%s",
printf("%s%s%s%04x|%04x@%x%s",
(m_core->v__DOT__r_bank==i)?"R":"[",
((m_core->v__DOT__bank_open)&(1<<i))?"+":" ",
((m_core->v__DOT__bank_closed)&(1<<i))?"-":" ",
m_core->v__DOT__bank_status[i],
m_sdram->m_bank[i].m_state&0x0f,
m_sdram->bank_state(i),
m_core->v__DOT__bank_address[i],
(m_core->v__DOT__r_nxt_bank==i)?"N":"]");
}
203,14 → 215,13
(m_core->v__DOT__need_close_bank)?"C":" ",
(m_core->v__DOT__need_open_bank)?"O":" ",
(m_core->v__DOT__valid_bank)?"V":" ",
(m_core->v__DOT__r_move)?"R":" ",
(m_core->v__DOT__maybe_close_next_bank)?"c":" ",
(m_core->v__DOT__maybe_open_next_bank)?"o":" ",
(m_core->v__DOT__pre_valid)?"p":" ",
(m_core->v__DOT__w_r_valid)?"r":" ",
(m_core->v__DOT__w_s_valid)?"s":" ");
(m_core->v__DOT__w_s_valid)?"s":" ",
(m_core->v__DOT__pre_ack)?"k":" ");
 
/*
// Refresh logic
printf(" F%s%05x:%x/%s",
(m_core->v__DOT__refresh_ztimer)?"Z":" ",
217,21 → 228,32
m_core->v__DOT__refresh_counter,
m_core->v__DOT__refresh_addr,
(m_core->v__DOT__need_refresh)?"N":" ");
*/
 
if (m_core->v__DOT__reset_override)
printf(" OVERRIDE");
//if(m_core->v__DOT__last_open_bank)printf(" LST-OPEN");
switch(cmd) {
switch(cmda) {
case DDR_MRSET: printf("%13s", " MRSET"); break;
case DDR_REFRESH: printf("%13s", " REFRESH"); break;
case DDR_PRECHARGE: printf("%9s%3s", " PRECHARGE", ((m_core->o_ddr_cmd_a>>6)&0x400)?"-ALL":""); break;
case DDR_ACTIVATE: printf("%13s", " ACTIVATE"); break;
case DDR_WRITE: printf("%13s", " WRITE"); break;
case DDR_READ: printf("%13s", " READ"); break;
case DDR_ZQS: printf("%13s", " ZQS"); break;
case DDR_NOOP: printf("%13s", " NOOP"); break;
default: printf(" UCMD(%02x)", cmda); break;
}
 
switch(cmdb) {
case DDR_MRSET: printf(" MRSET"); break;
case DDR_REFRESH: printf(" REFRESH"); break;
case DDR_PRECHARGE: printf(" PRECHARGE%s", (m_core->o_ddr_addr&0x400)?"-ALL":""); break;
case DDR_PRECHARGE: printf(" PRECHARGE%s", ((m_core->o_ddr_cmd_b>>6)&0x400)?"-ALL":""); break;
case DDR_ACTIVATE: printf(" ACTIVATE"); break;
case DDR_WRITE: printf(" WRITE"); break;
case DDR_READ: printf(" READ"); break;
case DDR_ZQS: printf(" ZQS"); break;
case DDR_NOOP: printf(" NOOP"); break;
default: printf(" Unknown-CMD(%02x)", cmd); break;
default: printf(" UCMD(%02x)", cmdb); break;
}
 
// Decode the command
277,9 → 299,9
assert(!m_core->o_wb_ack);
}
 
unsigned wb_read(unsigned a) {
unsigned long wb_read(unsigned a) {
int errcount = 0;
unsigned result;
unsigned long result;
 
printf("WB-READ(%08x)\n", a);
 
324,7 → 346,7
return result;
}
 
void wb_read(unsigned a, int len, unsigned *buf) {
void wb_read(unsigned a, int len, unsigned long *buf) {
int errcount = 0;
int THISBOMBCOUNT = BOMBCOUNT * len;
int cnt, rdidx, inc;
358,7 → 380,7
cnt += (s==0)?1:0;
if (m_core->o_wb_ack) {
buf[rdidx] = m_core->o_wb_data;
printf("WB-READ[%08x] = %08x\n", a+rdidx,
printf("WB-READ[%08x] = %016lx\n", a+rdidx,
m_core->o_wb_data);
if (buf[rdidx] != (*this)[a+rdidx]) {
printf("READ-FAIL\n");
374,7 → 396,7
tick();
if (m_core->o_wb_ack) {
buf[rdidx] = m_core->o_wb_data;
printf("WB-READ[%08x] = %08x\n", a+rdidx,
printf("WB-READ[%08x] = %016lx\n", a+rdidx,
m_core->o_wb_data);
if (buf[rdidx] != (*this)[a+rdidx]) {
printf("READ-FAIL\n");
399,14 → 421,15
assert(!m_core->o_wb_ack);
}
 
void wb_write(unsigned a, unsigned int v) {
void wb_write(unsigned a, unsigned long v) {
int errcount = 0;
 
printf("WB-WRITE(%08x) = %08x\n", a, v);
printf("WB-WRITE(%08x) = %016lx\n", a, v);
m_core->i_wb_cyc = 1;
m_core->i_wb_stb = 1;
m_core->i_wb_we = 1;
m_core->i_wb_addr= a & SDRAMMASK;
m_core->i_wb_sel = 0x0ff;
m_core->i_wb_data= v;
 
if (m_core->o_wb_stall)
431,7 → 454,7
assert(!m_core->o_wb_ack);
}
 
void wb_write(unsigned a, unsigned int ln, unsigned int *buf) {
void wb_write(unsigned a, unsigned int ln, unsigned long *buf) {
unsigned errcount = 0, nacks = 0;
 
m_core->i_wb_cyc = 1;
439,6 → 462,7
for(unsigned stbcnt=0; stbcnt<ln; stbcnt++) {
m_core->i_wb_we = 1;
m_core->i_wb_addr= (a+stbcnt) & SDRAMMASK;
m_core->i_wb_sel = 0x0ff;
m_core->i_wb_data= buf[stbcnt];
errcount = 0;
 
477,12 → 501,13
 
};
 
void uload(unsigned len, unsigned *buf) {
void uload(unsigned len, unsigned long *buf) {
FILE *fp = fopen("/dev/urandom", "r");
 
if ((NULL == fp)||(len != fread(buf, sizeof(unsigned), len, fp))) {
if ((NULL == fp)||(len != fread(buf, sizeof(unsigned long), len, fp))) {
for(int i=0; i<(int)len; i++)
buf[i] = rand();
buf[i] = (((unsigned long)rand())<<32)
|(((unsigned long)rand())&(-1l<<32));
} if (NULL == fp)
fclose(fp);
}
490,8 → 515,8
int main(int argc, char **argv) {
Verilated::commandArgs(argc, argv);
DDRSDRAM_TB *tb = new DDRSDRAM_TB;
unsigned *rdbuf, *mbuf;
unsigned mlen = (1<<(LGMEMSIZE-2));
unsigned long *rdbuf, *mbuf;
unsigned mlen = (1<<(LGMEMSIZE-3));
 
printf("Giving the core 140k cycles to start up\n");
// Before testing, let's give the unit time enough to warm up
505,8 → 530,8
mlen = 1<<16;
 
printf("Getting some memory ...\n");
rdbuf = new unsigned[mlen];
mbuf = new unsigned[mlen]; // Match buffer
rdbuf = new unsigned long[mlen];
mbuf = new unsigned long[mlen]; // Match buffer
printf("Charging my memory with random values\n");
uload(mlen, rdbuf);
 
522,24 → 547,25
 
#ifdef CASE_TESTS
{
unsigned v;
unsigned long v;
for(int i=0; i<8; i++) {
tb->wb_write(i, rdbuf[i]);
if ((v=tb->wb_read(i)) != rdbuf[i]) {
printf("CASE-1, %08x -> MEM[%08x] -> %08x FAILED (R/W not equal)\n", rdbuf[i], i, v);
printf("CASE-1, %16lx -> MEM[%08x] -> %16lx FAILED (R/W not equal)\n", rdbuf[i], i, v);
goto test_failure;
}
} else printf("MATCH[%d] = %16lx\n", i, rdbuf[i]);
}
}
 
// Now repeat, hitting a different bank with each command
{
unsigned v, a;
unsigned a;
unsigned long v;
for(int i=0; i<8; i++) {
a = 1087 + i*1031;
tb->wb_write(a, rdbuf[a]);
if ((v=tb->wb_read(a)) != rdbuf[a]) {
printf("CASE-2, %08x -> MEM[%08x] -> %08x FAILED (R/W not equal)\n", rdbuf[a], a, v);
printf("CASE-2, %016lx -> MEM[%08x] -> %016lx FAILED (R/W not equal)\n", rdbuf[a], a, v);
goto test_failure;
}
}
547,12 → 573,13
 
// And again, hitting the same bank with each command
{
unsigned v, a;
unsigned a;
unsigned long v;
for(int i=0; i<8; i++) {
a = 1109 + i*1024;
tb->wb_write(a, rdbuf[a]);
if ((v=tb->wb_read(a)) != rdbuf[a]) {
printf("CASE-3, %08x -> MEM[%08x] -> %08x FAILED (R/W not equal)\n", rdbuf[a], a, v);
printf("CASE-3, %016lx -> MEM[%08x] -> %016lx FAILED (R/W not equal)\n", rdbuf[a], a, v);
goto test_failure;
}
}
560,7 → 587,8
 
// Same thing, but writing all first before reading
{
unsigned v, a;
unsigned a;
unsigned long v;
for(int i=0; i<8; i++) {
a = 1109 + i*1024;
tb->wb_write(a, rdbuf[a]);
567,7 → 595,7
} for(int i=0; i<8; i++) {
a = 1109 + i*1024;
if ((v=tb->wb_read(a)) != rdbuf[a]) {
printf("CASE-4, %08x -> MEM[%08x] -> %08x FAILED (R/W not equal)\n", rdbuf[a], a, v);
printf("CASE-4, %016lx -> MEM[%08x] -> %016lx FAILED (R/W not equal)\n", rdbuf[a], a, v);
goto test_failure;
}
}
575,12 → 603,13
 
// And a quick pipeline test
{
unsigned v, mbuf[8], a = 379;
unsigned long v, mbuf[8];
unsigned a = 379;
tb->wb_write(0, 8, &rdbuf[379]);
for(int i=0; i<8; i++) {
a = 379+i;
if ((v=(*tb)[i]) != rdbuf[a]) {
printf("CASE-5, %08x -> MEM[%08x] -> %08x FAILED (R/W not equal)\n", rdbuf[a], i, v);
printf("CASE-5, %016lx -> MEM[%08x] -> %016lx FAILED (R/W not equal)\n", rdbuf[a], i, v);
goto test_failure;
}
} tb->wb_read(0, 8, mbuf);
587,7 → 616,7
for(int i=0; i<8; i++) {
a = 379+i;
if (mbuf[i] != rdbuf[a]) {
printf("CASE-6, %08x -> MEM[%08x] -> %08x FAILED (R/W not equal)\n", rdbuf[a], i, mbuf[i]);
printf("CASE-6, %016lx -> MEM[%08x] -> %016lx FAILED (R/W not equal)\n", rdbuf[a], i, mbuf[i]);
goto test_failure;
}
}
602,7 → 631,7
tb->wb_write(i, rdbuf[i]);
tb->wb_tick();
if ((*tb)[i] != rdbuf[i]) {
printf("WRITE[%06x] = %08x (Expecting %08x) FAILED\n",
printf("WRITE[%06x] = %016lx (Expecting %016lx) FAILED\n",
i, (*tb)[i], rdbuf[i]);
goto test_failure;
} if (tb->bombed())
614,14 → 643,14
// If we aren't doing the write test, we still need to charge
// the memory for the read test. Here we do it manually.
for(int i=0; i<(int)mlen; i++)
(*tb)[i] = rdbuf[i];
tb->set(i, rdbuf[i]);
#endif // !SINGULAR_WRITE && SINGULAR_READ
#endif // SINGULAR_WRITE
#ifdef SINGULAR_READ
for(int i=0; i<(int)mlen; i++) {
unsigned v;
unsigned long v;
if (rdbuf[i] != (v=tb->wb_read(i))) {
printf("READ[%06x] = %08x (Expecting %08x)\n",
printf("READ[%06x] = %016lx (Expecting %016lx)\n",
i, v, rdbuf[i]);
goto test_failure;
} if (tb->bombed())
639,9 → 668,9
if (tb->bombed())
goto test_failure;
for(int i=0; i<(int)mlen; i++) {
unsigned v;
unsigned long v;
if (rdbuf[i] != (v=(*tb)[i])) {
printf("V-WRITE[%06x] = %08x (Expecting %08x)\n",
printf("V-WRITE[%06x] = %016lx (Expecting %016lx)\n",
i, v, rdbuf[i]);
goto test_failure;
}
662,7 → 691,7
goto test_failure;
for(int i=0; i<(int)mlen; i++) {
if (rdbuf[i] != mbuf[i]) {
printf("V-READ[%06x] = %08x (Expecting %08x)\n",
printf("V-READ[%06x] = %016lx (Expecting %016lx)\n",
i, mbuf[i], rdbuf[i]);
goto test_failure;
}
681,7 → 710,7
tb->wb_write(i, nw, &rdbuf[i]);
for(int j=0; j<ln; j++) {
if ((*tb)[i+j] != rdbuf[i+j]) {
printf("P-WRITE[%06x] = %08x (Expecting %08x) FAILED\n",
printf("P-WRITE[%06x] = %016lx (Expecting %016lx) FAILED\n",
i, (*tb)[i], rdbuf[i]);
goto test_failure;
}
695,10 → 724,11
// If we aren't doing the write test, we still need to charge
// the memory for the read test. Here we do it manually.
for(int i=0; i<(int)mlen; i++)
(*tb)[i] = rdbuf[i];
tb->set(i, rdbuf[i]);
#endif
#endif
#ifdef PRIMEVEC_READ
printf("Starting the prime-vector read test\n");
{
int nr = 13;
for(int i=0; i<(int)mlen; i+=nr) {
706,7 → 736,7
tb->wb_read(i, nr, &mbuf[i]);
for(int j=0; j<ln; j++) {
if (mbuf[i+j] != rdbuf[i+j]) {
printf("P-READ[%06x] = %08x (Expecting %08x) FAILED\n",
printf("P-READ[%06x] = %016lx (Expecting %016lx) FAILED\n",
i, mbuf[i], rdbuf[i]);
goto test_failure;
}
725,7 → 755,7
int loc = (i*3889)&(mlen-1);
tb->wb_write(loc, rdbuf[loc]);
if ((*tb)[loc] != rdbuf[loc]) {
printf("R-WRITE[%06x] = %08x (Expecting %08x) FAILED\n",
printf("R-WRITE[%06x] = %016lx (Expecting %016lx) FAILED\n",
i, (*tb)[loc], rdbuf[loc]);
goto test_failure;
} if (tb->bombed())
735,7 → 765,7
#ifdef SKIP_READ
uload(mlen, rdbuf); // Get some new values
for(int i=0; i<(int)mlen; i++)
(*tb)[i] = rdbuf[i];
tb->set(i, rdbuf[i]);
#endif // !SKIP_WRITE && SKIP_READ
#endif
#ifdef SKIP_READ
743,7 → 773,7
int loc = (i*7477)&(mlen-1);
mbuf[loc] = tb->wb_read(loc);
if (mbuf[loc] != rdbuf[loc]) {
printf("R-READ[%06x] = %08x (Expecting %08x) FAILED\n",
printf("R-READ[%06x] = %016lx (Expecting %016lx) FAILED\n",
loc, mbuf[loc], rdbuf[loc]);
goto test_failure;
} if (tb->bombed())
/bench/cpp/pddrsim.h
0,0 → 1,71
////////////////////////////////////////////////////////////////////////////////
//
// Filename: pddrsim.h
//
// Project: A wishbone controlled DDR3 SDRAM memory controller.
//
// Purpose: To expand a DDR3 SDRAM controllers influence across multiple
// clocks. Hence, if the DDR3 SDRAM controller runs at half
// the clock rate of the DDR3-SDRAM, this will expand it to the full
// clock rate.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 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
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
#ifndef PDDRSIM_H
#define PDDRSIM_H
 
#include "ddrsdramsim.h"
 
class PDDRSIM : protected DDRSDRAMSIM {
public:
PDDRSIM(int lglen) : DDRSDRAMSIM(lglen) {};
unsigned long operator()(int, int, int,
unsigned, unsigned, unsigned long);
unsigned long operator[](unsigned addr) {
unsigned hdata, ldata;
unsigned long odata;
hdata = mem(addr<<1);
ldata = mem((addr<<1)+1);
 
odata = (((unsigned long)hdata)<<32)|((unsigned long)ldata);
return odata; };
void set(unsigned addr, unsigned long data) {
unsigned hdata, ldata;
hdata = (unsigned long)(data>>32);
ldata = (unsigned long)(data);
 
mem((addr<<1) ) = hdata;
mem((addr<<1)+1) = ldata;
};
unsigned bank_state(int bankid) {
return (m_bank[bankid].m_state & 0x0ffff); };
};
 
#endif
/bench/cpp/ddrsdramsim.cpp
38,21 → 38,29
#include <stdio.h>
#include <assert.h>
 
#include "ddrsdramsim.h"
 
#define PREFIX "DDR3-SDRAM"
const unsigned ckCL = 5,
ckRC = 10,
ckRAS = 7,
ckRFC = 320, // Clocks from refresh to activate
ckREFI = 1560; // 7.8us @ 200MHz = 7.8e-6 * 200e6 = 1560
/*
const unsigned nREF = 4,
ckREFIn = nREF*ckREFI - (nREF-1) * ckRFC;
*/
const unsigned nREF = 1,
ckREFIn = ckREFI;
const unsigned ckCL = 6,
ckCWL = 5,
ckRP = 6,
ckWR = 6,
ckRAS = 15,
ckRC = 20,
ckMRD = 4,
ckMOD = 12,
ckZQinit = 512,
ckODT = ckCWL-2,
ckRFC = 64, // Clocks from refresh to activate
ckREFI = 1560*NWIDTH, // 7.8us @ 200MHz = 7.8e-6 * 200e6 = 1560
DDR_MR2 = 0x0040 | (((ckCWL-5)&7)<<3),
DDR_MR1 = 0x0044,
DDR_MR0 = 0x0000 | (((ckCL-4)&0x07)<<4) | ((ckCL>11)?0x4:0)
|((ckWR==16)?0
:(ckWR>=8)?((((ckWR-8)>>1)+8)<<9)
:((ckWR-5+1)<<9)),
nREF = 1;
 
#include "ddrsdramsim.h"
 
BANKINFO::BANKINFO(void) {
m_state = 0; m_row = 0; m_wcounter = 0; m_min_time_before_precharge=0;
}
65,7 → 73,8
assert(m_state == 0);
break;
case DDR_PRECHARGE:
m_state = 6;
// assert((m_state&((1<<ckRP)-1)) == ((1<<ckRP)-1));
m_state &= -2;
// While the specification allows precharging an already
// precharged bank, we can keep that from happening
// here:
72,6 → 81,7
// assert(m_state&7);
// Only problem is, this will currently break our
// refresh logic.
/*
if (m_min_time_before_precharge != 0) {
printf("BANK-FAIL: TIME-BEFORE-PRECHARGE = %d (should be zero)\n", m_min_time_before_precharge);
assert(m_min_time_before_precharge == 0);
79,12 → 89,16
printf("BANK-FAIL: TIME-BEFORE-ACTIVATE = %d (should be zero)\n", m_min_time_before_activate);
assert(m_min_time_before_activate==0);
}
*/
break;
case DDR_ACTIVATE:
assert((m_state&((1<<ckRP)-1)) == 0);
if (((m_state&7)!=0)&&((addr&0x7fff) != m_row)) {
printf("BANK-FAIL: Attempt to Activate an already active bank without closing it first (m_state = %x)\n", m_state);
assert((m_state&7)==0);
}
 
/*
if (m_wcounter != 0) {
printf("BANK-FAIL: ACTIVATE too soon after write (wcounter = %d)\n", m_wcounter);
assert(m_wcounter == 0);
92,8 → 106,10
printf("BANK-FAIL: ACTIVATE too soon after last activate, (ctr=%d)\n", m_min_time_before_activate);
assert(m_min_time_before_activate==0);
}
*/
m_state = 1;
m_row = addr & 0x7fff;
printf("BANK -- Setting address to %04x\n", m_row);
m_min_time_before_precharge = ckRAS;
m_min_time_before_activate = ckRC;
break;
102,7 → 118,11
assert(m_wcounter == 0);
else
m_wcounter = 3+4+4;
assert((m_state&7) == 7);
if ((m_state&((1<<ckRP)-1)) != ((1<<ckRP)-1)) {
printf(PREFIX "::R/W Error: m_state = %08x, ckRP = %d (%08x)\n",
m_state, ckRP, ((1<<ckRP)-1));
assert((m_state&((1<<ckRP)-1)) == ((1<<ckRP)-1));
}
if (m_min_time_before_precharge)
m_min_time_before_precharge--;
if (m_min_time_before_activate)
109,7 → 129,7
m_min_time_before_activate--;
break;
case DDR_ZQS:
assert((m_state&7) == 0);
assert((m_state&((1<<ckRP)-1)) == 0);
if (m_min_time_before_precharge)
m_min_time_before_precharge--;
if (m_min_time_before_activate)
118,7 → 138,7
case DDR_NOOP:
m_state <<= 1;
m_state |= (m_state&2)>>1;
m_state &= 0x0f;
m_state &= ((1<<ckRP)-1);
if (m_min_time_before_precharge)
m_min_time_before_precharge--;
if (m_min_time_before_activate)
136,6 → 156,7
m_mem = new unsigned[m_memlen];
m_reset_state = 0;
m_reset_counts= 0;
assert(NTIMESLOTS > ckCL+3);
m_bus = new BUSTIMESLOT[NTIMESLOTS];
for(int i=0; i<NTIMESLOTS; i++)
m_bus[i].m_used = 0;
144,7 → 165,7
m_busloc = 0;
}
 
unsigned DDRSDRAMSIM::operator()(int reset_n, int cke,
unsigned DDRSDRAMSIM::apply(int reset_n, int cke,
int csn, int rasn, int casn, int wen,
int dqs, int dm, int odt, int busoe,
int addr, int ba, int data) {
156,11 → 177,12
m_reset_state = 0;
m_reset_counts = 0;
} else if (m_reset_state < 16) {
// printf(PREFIX "::Reset-CMD = %02x,BA=%d,ADDR=%04x, counts = %d\n", cmd, ba, addr, m_reset_counts);
switch(m_reset_state) {
case 0:
m_reset_counts++;
if (reset_n) {
assert(m_reset_counts > 40000);
assert(m_reset_counts > 40000*NWIDTH);
m_reset_counts = 0;
m_reset_state = 1;
} break;
167,7 → 189,7
case 1:
m_reset_counts++;
if (cke) {
assert(m_reset_counts > 100000);
assert(m_reset_counts > 100000*NWIDTH);
m_reset_counts = 0;
m_reset_state = 2;
} break;
175,25 → 197,26
m_reset_counts++;
assert(cke);
if (cmd != DDR_NOOP) {
assert(m_reset_counts > 147);
assert(m_reset_counts > (int)(ckRFC+2*NWIDTH));
m_reset_counts = 0;
m_reset_state = 3;
assert(cmd == DDR_MRSET);
// Set MR2
assert(ba == 2);
assert(addr == 0x040);
printf(PREFIX "::Checking DDR-MR2(%04x) against %04x\n", addr, DDR_MR2);
assert(addr == DDR_MR2);
} break;
case 3:
m_reset_counts++;
assert(cke);
if (cmd != DDR_NOOP) {
// assert(m_reset_counts > 3);
assert(m_reset_counts >= (int)ckMRD);
m_reset_counts = 0;
m_reset_state = 4;
assert(cmd == DDR_MRSET);
// Set MR1
assert(ba == 1);
assert(addr == 0x844);
assert(addr == DDR_MR1);
} break;
case 4:
m_reset_counts++;
200,13 → 223,13
assert(cke);
if (cmd != DDR_NOOP) {
printf(PREFIX "::RESET-CMD[4]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
assert(m_reset_counts > 3);
assert(m_reset_counts >= (int)ckMRD);
m_reset_counts = 0;
m_reset_state = 5;
assert(cmd == DDR_MRSET);
// Set MR0
assert(ba == 0);
assert(addr == 0x210);
assert(addr == DDR_MR0);
} break;
case 5:
m_reset_counts++;
213,7 → 236,7
assert(cke);
if (cmd != DDR_NOOP) {
printf(PREFIX "::RESET-CMD[5]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
assert(m_reset_counts > 11);
assert(m_reset_counts >= (int)ckMOD);
m_reset_counts = 0;
m_reset_state = 6;
assert(cmd == DDR_ZQS);
224,7 → 247,7
assert(cke);
if (cmd != DDR_NOOP) {
printf(PREFIX "::RESET-CMD[6]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
assert(m_reset_counts > 512);
assert(m_reset_counts >= (int)ckZQinit);
m_reset_counts = 0;
m_reset_state = 7;
assert(cmd == DDR_PRECHARGE);
235,7 → 258,7
assert(cke);
if (cmd != DDR_NOOP) {
printf(PREFIX "::RESET-CMD[7]: %d:%08x[%d]@0x%04x\n", cmd, m_reset_counts, ba, addr);
assert(m_reset_counts > 3);
assert(m_reset_counts >= (int)ckRP);
m_reset_counts = 0;
m_reset_state = 8;
assert(cmd == DDR_REFRESH);
245,7 → 268,7
m_reset_counts++;
assert(cke);
assert(cmd == DDR_NOOP);
if (m_reset_counts > 140) {
if (m_reset_counts > (int)ckRFC) {
m_reset_state = 16;
printf(PREFIX ": Leaving reset state\n");
}
282,7 → 305,10
// In operational mode!!
 
m_clocks_since_refresh++;
assert(m_clocks_since_refresh < (int)ckREFIn);
if (m_clocks_since_refresh > (int)ckREFI) {
printf(PREFIX "::ERROR! Clocks since refresh = %d, which isn\'t less than %d\n", m_clocks_since_refresh, ckREFI);
}
assert(m_clocks_since_refresh <= (int)ckREFI);
switch(cmd) {
case DDR_MRSET:
assert(0&&"Modes should only be set in reset startup");
298,9 → 324,11
case DDR_PRECHARGE:
if (addr & 0x400) {
// Precharge all
printf(PREFIX "::Precharging all banks\n");
for(int i=0; i<NBANKS; i++)
m_bank[i].tick(DDR_PRECHARGE,0);
} else {
printf(PREFIX "::Precharging bank [%d]\n", ba);
m_bank[ba].tick(DDR_PRECHARGE,0);
for(int i=0; i<NBANKS; i++)
if (ba != i)
308,7 → 336,10
}
break;
case DDR_ACTIVATE:
assert(m_clocks_since_refresh >= (int)ckRFC);
if (m_clocks_since_refresh < (int)ckRFC) {
printf(PREFIX "::ACTIVATE -- not enough clocks since refresh, %d < %d should be true\n", m_clocks_since_refresh, ckRFC);
assert(m_clocks_since_refresh >= (int)ckRFC);
}
printf(PREFIX "::Activating bank %d, address %08x\n", ba, addr);
m_bank[ba].tick(DDR_ACTIVATE,addr);
for(int i=0; i<NBANKS; i++)
330,7 → 361,7
caddr >>= 1;
 
BUSTIMESLOT *tp;
int offset = m_busloc+ckCL+1;
int offset = m_busloc+ckCWL+1;
 
tp = &m_bus[(offset+0)&(NTIMESLOTS-1)];
// printf("Setting bus timeslots from (now=%d)+%d=%d to now+%d+3\n", m_busloc, ckCL,(m_busloc+ckCL)&(NTIMESLOTS-1), ckCL);
369,7 → 400,12
caddr >>= 1;
 
BUSTIMESLOT *tp;
 
printf(PREFIX"::READ(%03x:%d:%03x => %08x) Queuing %08x:%08x:%08x:%08x\n",
m_bank[ba].m_row, ba, addr,
caddr,
m_mem[caddr ], m_mem[caddr+1],
m_mem[caddr+2], m_mem[caddr+3]);
int offset = (m_busloc+ckCL+1)&(NTIMESLOTS-1);
tp = &m_bus[(offset)&(NTIMESLOTS-1)];
tp->m_data = m_mem[caddr];
418,7 → 454,7
break;
}
} if (flag) {
printf("DQS = %d BUSLOC = %d\n", dqs, (m_busloc+1)&(NTIMESLOTS-1));
printf(PREFIX "::DQS = %d BUSLOC = %d\n", dqs, (m_busloc+1)&(NTIMESLOTS-1));
for(int i=0; i<5; i++) {
int bl = (m_busloc+1+i)&(NTIMESLOTS-1);
nxtts = &m_bus[bl];
434,9 → 470,15
}
 
ts = &m_bus[(m_busloc+1)&(NTIMESLOTS-1)];
if (dqs)
if (dqs) {
/*
if ((!ts->m_rtt)||(!m_last_rtt)) {
printf(PREFIX "ODT(dqs is true) m_rtt is %s and last_rtt is %s. Both should be true if DQS. (ERROR!)\n",
(ts->m_rtt)?"true":"false",
(m_last_rtt)?"true":"false");
} */
assert((ts->m_rtt)&&(m_last_rtt));
else if (!m_last_dqs)
} else if (!m_last_dqs)
assert(!m_last_rtt);
}
 
445,6 → 487,7
ts = &m_bus[m_busloc];
nxtts = &m_bus[(m_busloc+1)&(NTIMESLOTS-1)];
unsigned vl = ts->m_data;
 
assert( ((!ts->m_used)||(busoe))
|| ((ts->m_used)&&(ts->m_read)&&(!busoe))
|| ((ts->m_used)&&(!ts->m_read)&&(busoe))
462,12 → 505,19
assert(!dqs);
 
assert((!ts->m_used)||(ts->m_addr < (unsigned)m_memlen));
if ((ts->m_used)&&(!ts->m_read)&&(!dm)) {
printf(PREFIX "::Setting MEM[%08x] = %08x\n", ts->m_addr, data);
m_mem[ts->m_addr] = data;
if ((ts->m_used)&&(!ts->m_read)&&(dm != 0x0f)) {
printf(PREFIX "::Setting MEM[%08x] = %08x (%02x)\n", ts->m_addr, data, dm);
unsigned mask = 0;
if (dm&0x08) mask = 0x0ff;
mask <<= 8; if (dm&0x004) mask |= 0x0ff;
mask <<= 8; if (dm&0x002) mask |= 0x0ff;
mask <<= 8; if (dm&0x001) mask |= 0x0ff;
m_mem[ts->m_addr] = (data & (~mask)) | (m_mem[ts->m_addr]&mask);
} else if ((ts->m_used)&&(ts->m_read)) {
printf(PREFIX ":: %08x\n", vl);
}
 
m_bus[(m_busloc+3)&(NTIMESLOTS-1)].m_rtt = (odt)&&(reset_n);
m_bus[(m_busloc+ckODT-1)&(NTIMESLOTS-1)].m_rtt = (odt)&&(reset_n);
ts->m_used = 0;
ts->m_read = 0;
ts->m_addr = -1;
/bench/cpp/Makefile
44,7 → 44,7
VROOT := /usr/share/verilator
VINC := -I$(VROOT)/include -I$(VOBJDR)
CFLAGS := -Wall -c -Og -g -I. $(VINC)
SOURCES := ddrsdramsim.cpp ddrsdram_tb.cpp
SOURCES := pddrsim.cpp ddrsdramsim.cpp ddrsdram_tb.cpp
VOBJDR := $(RTLD)/obj_dir
VLIB := $(VROOT)/include/verilated.cpp
 
54,14 → 54,17
$(OBJDIR)/:
@bash -c "if [ ! -e $(OBJDIR) ]; then mkdir -p $(OBJDIR); fi"
 
$(OBJDIR)/ddrsdramsim.o: ddrsdramsim.cpp ddrsdramsim.h $(VOBJDR)/Vwbddrsdram.h
$(OBJDIR)/pddrsim.o: pddrsim.cpp pddrsim.h ddrsdramsim.h
$(CXX) $(CFLAGS) pddrsim.cpp -o $@
# $(VOBJDR)/Vwbddrsdram.h
$(OBJDIR)/ddrsdramsim.o: ddrsdramsim.cpp ddrsdramsim.h
$(CXX) $(CFLAGS) ddrsdramsim.cpp -o $@
$(OBJDIR)/verilated.o: $(VLIB) $(OBJDIR)/
$(OBJDIR)/verilated.o: $(VLIB)
$(CXX) $(CFLAGS) $(VLIB) -o $@
$(OBJDIR)/ddrsdram_tb.o: ddrsdram_tb.cpp ddrsdramsim.h $(VOBJDR)/Vwbddrsdram.h
$(OBJDIR)/ddrsdram_tb.o: ddrsdram_tb.cpp pddrsim.h $(VOBJDR)/Vwbddrsdram.h
$(CXX) $(CFLAGS) ddrsdram_tb.cpp -o $@
 
OBJECTS := ddrsdramsim.o ddrsdram_tb.o verilated.o
OBJECTS := ddrsdramsim.o pddrsim.o ddrsdram_tb.o verilated.o
OBJECTSDR:= $(addprefix $(OBJDIR)/,$(OBJECTS))
ddrsdram_tb: $(OBJECTSDR) $(VOBJDR)/Vwbddrsdram__ALL.a
$(CXX) -Wall $(INCS) $^ -o $@
/rtl/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,131 → 77,60
`define DDR_BABITS 3 // BABITS are really from 18:16, they are 3 bits
`define DDR_ADDR_BITS 14
//
`define BUSREG 7
`define BUSNOW 8
 
//
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,
CKXPR = CKRFC+5+2; // Clocks per tXPR timeout
input i_clk, i_reset;
i_wb_sel,
// Wishbone outputs
o_wb_ack, o_wb_stall, o_wb_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);
// 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
203,7 → 139,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;
238,9 → 174,15
reset_timer <= reset_instruction[16:0];
end
wire [16:0] w_ckXPR = CKXPR, w_ckRST = 4, w_ckRP = 3,
w_ckRFC_first = CKRFC-2-9;
wire [16:0] w_ckXPR, w_ckRFC_first;
wire [13:0] w_MR0, w_MR1, w_MR2;
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, ??
250,60 → 192,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_MRSET, 3'h2,
3'h0, 2'b00, 1'b0, 1'b0, 1'b1, 3'b0, 3'b0 }; // MRS2
// 3. Wait 4 clocks (tMRD)
5'h4: reset_instruction <= { 4'h7, `DDR_NOOP, 17'h02 };
// 5. Set MR1
5'h5: reset_instruction <= { 4'h3, `DDR_MRSET, 3'h1,
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
// 7. Wait another 4 clocks
5'h6: reset_instruction <= { 4'h7, `DDR_NOOP, 17'h02 };
// 8. Send MRS0
5'h7: reset_instruction <= { 4'h3, `DDR_MRSET, 3'h0,
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
3'b01, // High 3-bits, CAS latency (=4'b0010 = 4'd5)
1'b0, // Read burst type = nibble sequential
1'b0, // Low bit of cas latency
2'b0 }; // Burst length = 8 (Fixed)
// 9. Wait tMOD, is max(12 clocks, 15ns)
5'h8: reset_instruction <= { 4'h7, `DDR_NOOP, 17'h0a };
// 10. Issue a ZQCL command to start ZQ calibration, A10 is high
// 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
5'ha: reset_instruction <= { 4'h7, `DDR_NOOP, 17'd512 };
//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'hb: reset_instruction <= { 4'h3, `DDR_PRECHARGE, 6'h0, 1'b1, 10'h0 };
// 13. Wait for the precharge to complete
5'hc: reset_instruction <= { 4'h7, `DDR_NOOP, w_ckRP };
// 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'hd: reset_instruction <= { 4'h3, `DDR_REFRESH, 17'h00 };
// 15. Wait for the auto refresh to complete
5'he: reset_instruction <= { 4'h7, `DDR_NOOP, w_ckRFC_first };
// Two Auto Refresh commands
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)
311,39 → 229,218
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 banks_are_closing, all_banks_closed;
reg [3:0] bank_status [0:7];
reg [CKRP:0] bank_status [0:7];
reg [13:0] bank_address [0:7];
reg [3:0] bank_wr_ck [0:7]; // tWTR
reg bank_wr_ckzro [0:7]; // tWTR
351,28 → 448,20
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 = 8'h00;
initial bank_open = 0;
initial bank_closed = 8'hff;
always @(posedge i_clk)
begin
bank_status[0] <= { bank_status[0][2:0], bank_status[0][0] };
bank_status[1] <= { bank_status[1][2:0], bank_status[1][0] };
bank_status[2] <= { bank_status[2][2:0], bank_status[2][0] };
bank_status[3] <= { bank_status[3][2:0], bank_status[3][0] };
bank_status[4] <= { bank_status[4][2:0], bank_status[4][0] };
bank_status[5] <= { bank_status[5][2:0], bank_status[5][0] };
bank_status[6] <= { bank_status[6][2:0], bank_status[6][0] };
bank_status[7] <= { bank_status[7][2:0], bank_status[7][0] };
all_banks_closed <= (bank_status[0][2:0] == 3'b00)
&&(bank_status[1][2:0] == 3'b00)
&&(bank_status[2][2:0] == 3'b00)
&&(bank_status[3][2:0] == 3'b00)
&&(bank_status[4][2:0] == 3'b00)
&&(bank_status[5][2:0] == 3'b00)
&&(bank_status[6][2:0] == 3'b00)
&&(bank_status[7][2:0] == 3'b00);
bank_status[0] <= { bank_status[0][(CKRP-1):0], bank_status[0][0] };
bank_status[1] <= { bank_status[1][(CKRP-1):0], bank_status[1][0] };
bank_status[2] <= { bank_status[2][(CKRP-1):0], bank_status[2][0] };
bank_status[3] <= { bank_status[3][(CKRP-1):0], bank_status[3][0] };
bank_status[4] <= { bank_status[4][(CKRP-1):0], bank_status[4][0] };
bank_status[5] <= { bank_status[5][(CKRP-1):0], bank_status[5][0] };
bank_status[6] <= { bank_status[6][(CKRP-1):0], bank_status[6][0] };
bank_status[7] <= { bank_status[7][(CKRP-1):0], bank_status[7][0] };
 
bank_wr_ck[0] <= (|bank_wr_ck[0])?(bank_wr_ck[0]-4'h1):4'h0;
bank_wr_ck[1] <= (|bank_wr_ck[1])?(bank_wr_ck[1]-4'h1):4'h0;
392,23 → 481,23
bank_wr_ckzro[6] <= (bank_wr_ck[6][3:1]==3'b00);
bank_wr_ckzro[7] <= (bank_wr_ck[7][3:1]==3'b00);
 
bank_open[0] <= (bank_status[0][1:0] == 2'h3);
bank_open[1] <= (bank_status[1][1:0] == 2'h3);
bank_open[2] <= (bank_status[2][1:0] == 2'h3);
bank_open[3] <= (bank_status[3][1:0] == 2'h3);
bank_open[4] <= (bank_status[4][1:0] == 2'h3);
bank_open[5] <= (bank_status[5][1:0] == 2'h3);
bank_open[6] <= (bank_status[6][1:0] == 2'h3);
bank_open[7] <= (bank_status[7][1:0] == 2'h3);
bank_open[0] <= (bank_status[0][(CKRP-2):0] =={(CKRP-1){1'b1}});
bank_open[1] <= (bank_status[1][(CKRP-2):0] =={(CKRP-1){1'b1}});
bank_open[2] <= (bank_status[2][(CKRP-2):0] =={(CKRP-1){1'b1}});
bank_open[3] <= (bank_status[3][(CKRP-2):0] =={(CKRP-1){1'b1}});
bank_open[4] <= (bank_status[4][(CKRP-2):0] =={(CKRP-1){1'b1}});
bank_open[5] <= (bank_status[5][(CKRP-2):0] =={(CKRP-1){1'b1}});
bank_open[6] <= (bank_status[6][(CKRP-2):0] =={(CKRP-1){1'b1}});
bank_open[7] <= (bank_status[7][(CKRP-2):0] =={(CKRP-1){1'b1}});
 
bank_closed[0] <= (bank_status[0][0] == 1'b0);
bank_closed[1] <= (bank_status[1][0] == 1'b0);
bank_closed[2] <= (bank_status[2][0] == 1'b0);
bank_closed[3] <= (bank_status[3][0] == 1'b0);
bank_closed[4] <= (bank_status[4][0] == 1'b0);
bank_closed[5] <= (bank_status[5][0] == 1'b0);
bank_closed[6] <= (bank_status[6][0] == 1'b0);
bank_closed[7] <= (bank_status[7][0] == 1'b0);
bank_closed[0] <= (bank_status[0][(CKRP-3):0] == 0);
bank_closed[1] <= (bank_status[1][(CKRP-3):0] == 0);
bank_closed[2] <= (bank_status[2][(CKRP-3):0] == 0);
bank_closed[3] <= (bank_status[3][(CKRP-3):0] == 0);
bank_closed[4] <= (bank_status[4][(CKRP-3):0] == 0);
bank_closed[5] <= (bank_status[5][(CKRP-3):0] == 0);
bank_closed[6] <= (bank_status[6][(CKRP-3):0] == 0);
bank_closed[7] <= (bank_status[7][(CKRP-3):0] == 0);
 
if (w_this_rw_move)
bank_wr_ck[rw_cmd[16:14]] <= (rw_cmd[`DDR_WEBIT])? 4'h0
424,205 → 513,91
bank_status[5][0] <= 1'b0;
bank_status[6][0] <= 1'b0;
bank_status[7][0] <= 1'b0;
banks_are_closing <= 1'b1;
bank_open <= 0;
bank_closed <= 8'hff;
bank_open <= 8'h00;
end else if (need_close_bank)
begin
bank_status[close_bank_cmd[16:14]]
<= { bank_status[close_bank_cmd[16:14]][2:0], 1'b0 };
<= { 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]][2:0], 1'b1 };
// bank_status[activate_bank_cmd[16:14]][0] <= 1'b1;
all_banks_closed <= 1'b0;
banks_are_closing <= 1'b0;
<= { bank_status[activate_bank_cmd[16:14]][(CKRP-1):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]]
<= { bank_status[maybe_close_cmd[16:14]][2:0], 1'b0 };
<= { bank_status[maybe_close_cmd[16:14]][(CKRP-1):0], 1'b0 };
bank_open[maybe_close_cmd[16:14]] <= 1'b0;
end else if (maybe_open_next_bank)
begin
bank_status[maybe_open_cmd[16:14]]
<= { bank_status[maybe_open_cmd[16:14]][2:0], 1'b1 };
// bank_status[activate_bank_cmd[16:14]][0] <= 1'b1;
all_banks_closed <= 1'b0;
banks_are_closing <= 1'b0;
<= { bank_status[maybe_open_cmd[16:14]][(CKRP-1):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;
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, 17'd10 };
4'h2: refresh_instruction <= { 3'h4, `DDR_PRECHARGE, 17'h0400 };
4'h3: refresh_instruction <= { 3'h6, `DDR_NOOP, 17'd2 };
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;
assign w_ckREFI_left[12:0] = CKREFI-CKRFC-2-19;
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, 17'd10 };
3'h2: refresh_instruction <= { 3'h4, `DDR_PRECHARGE, 17'h0400 };
3'h3: refresh_instruction <= { 3'h6, `DDR_NOOP, 17'd2 };
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_active, bus_read, bus_new, bus_ack;
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?
bus_active[BUSNOW:0] <= { bus_active[(BUSNOW-1):0], 1'b0 };
// 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_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_ack[BUSNOW:0] <= { bus_ack[(BUSNOW-1):0], 1'b0 };
//
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)
632,8 → 607,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
 
//
//
646,25 → 625,21
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;
 
assign w_r_valid = (pre_valid)&&(r_pending)
&&(bank_status[r_bank][1])
&&(bank_status[r_bank][(CKRP-2)])
&&(bank_address[r_bank]==r_row)
&&((r_we)||(bank_wr_ckzro[r_bank]));
assign w_s_valid = (pre_valid)&&(s_pending)
&&(bank_status[s_bank][1])
&&(bank_status[s_bank][(CKRP-2)])
&&(bank_address[s_bank]==s_row)
&&((s_we)||(bank_wr_ckzro[s_bank]));
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)
678,8 → 653,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;
689,14 → 664,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)
709,12 → 692,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
 
760,9 → 742,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;
775,9 → 756,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
835,108 → 816,99
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;
 
// The bus R/W FIFO
wire w_bus_fifo_read_next_transaction;
assign w_bus_fifo_read_next_transaction = (bus_ack[`BUSREG]);
assign w_bus_fifo_read_next_transaction = (bus_ack[BUSREG]);
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));
ddr_odt <= bus_odt[BUSREG];
 
always @(posedge i_clk)
o_wb_ack <= pre_ack;

powered by: WebSVN 2.1.0

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