diff --git a/dram/resources/configs/addressConfig.xml b/dram/resources/configs/addressConfig.xml
index 1dc6c4eb..7494e586 100755
--- a/dram/resources/configs/addressConfig.xml
+++ b/dram/resources/configs/addressConfig.xml
@@ -16,6 +16,12 @@
-
+
+
+
diff --git a/dram/resources/scripts/metrics.py b/dram/resources/scripts/metrics.py
index c5303e55..c6c18641 100644
--- a/dram/resources/scripts/metrics.py
+++ b/dram/resources/scripts/metrics.py
@@ -1,17 +1,48 @@
import sys
import sqlite3
-
metrics = []
+threadMetrics = []
def metric(function):
metrics.append(function)
return function
-@metric
-def average_response_latency(connection):
+def threadMetric(function):
+ threadMetrics.append(function)
+ return function
+
+def getThreads(connection):
cursor = connection.cursor()
- cursor.execute("SELECT avg(end-begin) FROM ranges")
+ cursor.execute("SELECT DISTINCT(TThread) FROM transactions WHERE TThread != 0 ORDER BY TThread")
+ result = []
+ for currentRow in cursor:
+ result.append(currentRow[0])
+ return result
+
+def getNumberOfBanks(connection):
+ cursor = connection.cursor()
+ cursor.execute("SELECT NumberOfBanks FROM generalInfo")
+ result = cursor.fetchone()
+ return result[0]
+
+
+@metric
+def average_response_latency_in_ns(connection):
+ cursor = connection.cursor()
+ cursor.execute("""SELECT avg(ranges.end-ranges.begin) FROM transactions INNER JOIN ranges
+ ON transactions.range = ranges.ID where TThread != 0""")
+
+ result = cursor.fetchone()
+ return round(result[0],1)
+
+@threadMetric
+def average_response_latency_in_ns(connection, thread):
+ cursor = connection.cursor()
+ query = """SELECT avg(ranges.end-ranges.begin) FROM transactions INNER JOIN ranges
+ ON transactions.range = ranges.ID where TThread = :Thread """
+
+ cursor.execute(query, {"Thread": thread})
result = cursor.fetchone()
return round(result[0],1)
@@ -22,6 +53,55 @@ def number_of_activates(connection):
result = cursor.fetchone()
return result[0]
+@metric
+def number_of_precharges(connection):
+ cursor = connection.cursor()
+ cursor.execute("SELECT COUNT(*) FROM Phases WHERE PhaseName IN ('PRE','PRE_ALL','RDA','WRA')")
+ result = cursor.fetchone()
+ return result[0]
+
+def passRatio(connection):
+
+ numberOfPassWins = {}
+ numberOfPassLosses = {}
+
+ for thread in getThreads(connection):
+ numberOfPassWins[thread] = 0
+ numberOfPassLosses[thread] = 0
+
+ for bankNumber in range(getNumberOfBanks(connection)):
+ cursor = connection.cursor()
+ query = """SELECT begin,end,transactions.ID,TThread,
+ TBank from transactions inner join ranges on transactions.range = ranges.id WHERE TBank = :Bank AND TThread != 0"""
+ cursor.execute(query, {"Bank":bankNumber})
+
+ for passedRequest in cursor:
+ passedBegin = passedRequest[0]
+ passedEnd = passedRequest[1]
+ passedId = passedRequest[2]
+ passedThread = passedRequest[3]
+
+ cursor2 = connection.cursor()
+ query2 = """SELECT begin,end,transactions.ID,TThread,
+ TBank from transactions inner join ranges on transactions.range = ranges.id
+ WHERE TBank = :Bank AND :Begin> self.__dramConfigReader.startBits[element] & self.onesMask(self.__dramConfigReader.endBits[element] - self.__dramConfigReader.startBits[element] + 1)
+ return (address >> self.__dramConfigReader.startBits[element]) & self.onesMask(self.__dramConfigReader.endBits[element] - self.__dramConfigReader.startBits[element] + 1)
def formatStlLine(self, line):
try:
found = re.search('0x[0-9,a-f]+', line).group(0)
address = int(found, 16)
- decodedAddress = '[Channel: {0} Bank: {1} Row:{2} Column: {3}]'.format(self.parseAttributeFromAddress(address, 'channel'),
- self.parseAttributeFromAddress(address, 'bank'), self.parseAttributeFromAddress(address, 'row'), self.parseAttributeFromAddress(address, 'colum'))
+ decodedAddress = '[Channel: {0} Bank: {0} Row:{1} Col:{2}]'.format(self.parseAttributeFromAddress(address, 'channel'),
+ self.parseAttributeFromAddress(address, 'bank'), self.parseAttributeFromAddress(address, 'row'), self.parseAttributeFromAddress(address, 'colum'))
return line.replace("\n", " ") + decodedAddress
except AttributeError:
return ''
@@ -54,9 +55,11 @@ class StlReader:
def printStlPretty(self, filename):
f = open(filename)
for line in f.readlines():
- print(self.formatStlLine(line))
-
-
+ #print(self.formatStlLine(line))
+ found = re.search('0x[0-9,a-f]+', line).group(0)
+ address = int(found, 16)
+ print(format(address, '032b') + " " + self.formatStlLine(line))
+
class StlGenerator:
__actions = []
__time = 0
diff --git a/dram/resources/scripts/tests.py b/dram/resources/scripts/tests.py
index 426a853a..46faa6be 100644
--- a/dram/resources/scripts/tests.py
+++ b/dram/resources/scripts/tests.py
@@ -9,10 +9,11 @@ class DramConfig(object):
nActivateWindow = 0
burstLengtht = 2
clk = numberOfBanks = 0
- tRP = tRAS = tRC = tRRD = tRCD = tTAW = tRL = tWL = tWTR = 0
+ tRP = tRAS = tRC = tRRD = tRCD = tTAW = tRL = tWL = tWTR = tRFC = tWR = 0
+ tReadLength = tWriteLength = 0
def clkAlign(self, value):
- return math.ceil(value/self.clk)*self.clk
+ return math.ceil(1.0*value/self.clk)*self.clk
def parseFromXml(self):
self.clk = 6
@@ -28,7 +29,12 @@ class DramConfig(object):
self.tRL = 3*self.clk
self.tWL = 1*self.clk
self.tWTR = 3*self.clk
+ self.tWR = 2*self.clk
self.tTAW = self.clkAlign(50)
+ self.tRFC = self.clkAlign(130)
+
+ self.tReadLength = self.tRL + self.burstLength * self.clk
+ self.tWriteLength = self.tWL + (self.burstLength - 1) *self.clk
def __init__(self):
self.parseFromXml()
@@ -67,180 +73,257 @@ def commands_are_clockaligned(connection):
"""Checks that all commands on the command bus are aligned to the system clock"""
passedTest = True
cursor = connection.cursor()
- cursor.execute("SELECT ID, PhaseBegin, PhaseEnd from Phases WHERE PhaseName NOT IN ('REQ','RESP') ORDER BY PhaseBegin")
- lastRow = cursor.fetchone()
+ query = "select ID,PhaseBegin,PhaseEnd from phases where phaseName NOT IN ('REQ','RESP') AND (phaseBegin%:clk!=0 OR phaseEnd%:clk!=0)"
+ cursor.execute(query, {"clk": 6})
- for currentRow in cursor:
- phaseBegin = currentRow[1]
- phaseEnd = currentRow[2]
- if(phaseBegin % dramconfig.clk != 0):
- return TestFailed("Command with PhaseID {0} starts at {1} and is not aligned to system clock ({2})".format(
- currentRow[0], formatTime(phaseBegin), formatTime(dramconfig.clk)))
- if(phaseEnd % dramconfig.clk != 0):
- return TestFailed("Command with PhaseID {0} end at {1} and is not aligned to system clock ({2})".format(
- currentRow[0], formatTime(phaseEnd), formatTime(dramconfig.clk)))
+ result = cursor.fetchone()
+
+ if(result != None):
+ return TestFailed("Command with PhaseID {0} starts at {1} and ends at, which is not aligned to system clock ({2})".format(
+ result[0], formatTime(result[1]), formatTime(result[2]), formatTime(dramconfig.clk)))
+
return TestSuceeded()
@test
def commandbus_slots_are_used_once(connection):
"""Checks that no two phases on the command bus start at the same time"""
cursor = connection.cursor()
- cursor.execute("SELECT ID,PhaseBegin from Phases WHERE PhaseName NOT IN ('REQ', 'RESP') ORDER BY PhaseBegin")
- lastRow = cursor.fetchone()
+ cursor.execute("SELECT PhaseBegin,count FROM (SELECT phaseBegin,count(phasebegin) AS count FROM Phases WHERE PhaseName NOT IN ('RESP','REQ') GROUP BY phaseBegin) WHERE count>1")
+ result = cursor.fetchone()
+
+ if(result != None):
+ return TestFailed("Slot on commandbus at time {0} is used twice".format(formatTime(result[0])))
- for currentRow in cursor:
- if(lastRow[1] != currentRow[1]):
- lastRow = currentRow
- else:
- return TestFailed("Commandbus slot is used twice by commands with PhaseID {0} and {1}".format(lastRow[0], currentRow[0]))
return TestSuceeded()
-# ----------- precharge checks ---------------------------------------
+@test
+def command_sequences_are_valid(connection):
+ cursor = connection.cursor()
+ cursor.execute("SELECT group_concat(phaseName),transact FROM phases GROUP BY transact")
-# ----------- activate checks ---------------------------------------
+ validSequences = set(['AUTO_REFRESH','PDNA','PDNP','SREF',
+ 'PRE,AUTO_REFRESH', 'PRE_ALL,AUTO_REFRESH',
+ 'REQ,RD,RESP', 'REQ,WR,RESP', 'REQ,RDA,RESP', 'REQ,WRA,RESP',
+ 'REQ,ACT,RD,RESP', 'REQ,ACT,WR,RESP', 'REQ,ACT,RDA,RESP', 'REQ,ACT,WRA,RESP',
+ 'REQ,PRE,ACT,RD,RESP', 'REQ,PRE,ACT,WR,RESP', 'REQ,PRE,ACT,RDA,RESP', 'REQ,PRE,ACT,WRA,RESP'
+ ])
-# @test
-# def precharge_before_activate(connection):
-# """Checks that all activate commands are preceeded by a precharge or a refresh or a powerdown"""
-# cursor = connection.cursor()
-# query = """SELECT Phases.ID, PhaseName, PhaseBegin FROM Transactions INNER JOIN Phases ON Phases.Transact = Transactions.ID
-# WHERE (TBank = :bank AND PhaseName IN ('ACT','PRE','REFB')) OR PhaseName IN ('REFA','SREF','PDNP','PDNA') ORDER BY PhaseBegin"""
-
-# for bankNumber in range(dramconfig.numberOfBanks):
-# cursor.execute(query,{"bank": bankNumber})
-# lastRow = cursor.fetchone()
-
-# for currentRow in cursor:
-# if(lastRow[1] != currentRow[1] or currentRow[1] != 'ACT'):
-# lastRow = currentRow
-# else:
-# return TestFailed("No precharge between activates with PhaseID {0} and {1}".format(lastRow[0], currentRow[0]))
-# return TestSuceeded()
-
-# @test
-# def activate_to_activate(connection):
-# """Checks minimal time between two activates (JEDEC 229, P. 27)"""
-# cursor = connection.cursor()
-# cursor.execute("SELECT ID,PhaseBegin from Phases WHERE PhaseName = 'ACT' ORDER BY PhaseBegin")
-# lastRow = cursor.fetchone()
-
-# for currentRow in cursor:
-# timeBetweenActivates = currentRow[1] - lastRow[1];
-# if(timeBetweenActivates < dramconfig.tRRD):
-# return TestFailed("Activates with PhaseIDs {0} and {1} are {2} apart. Minimum time between two activates is {3}".format(currentRow[0], lastRow[0],formatTime(timeBetweenActivates), dramconfig.tRRD))
-# else:
-# lastRow = currentRow
-# return TestSuceeded()
-
-
-# @test
-# def activate_to_activate_on_same_bank(connection):
-# """Checks minimal time between two activates on the same bank (JEDEC 229, P. 27)"""
-# cursor = connection.cursor()
-# query = "SELECT Phases.ID,PhaseBegin from Phases INNER JOIN Transactions ON Phases.Transact = Transactions.ID WHERE PhaseName = 'ACT' AND TBANK = :bank ORDER BY PhaseBegin"
+ for currentRow in cursor:
+ commandSequence = currentRow[0]
+ if(commandSequence not in validSequences):
+ return TestFailed("Transaction {0} generated invalid command sequence {1}".format(currentRow[1], commandSequence))
-# for bankNumber in range(dramconfig.numberOfBanks):
-# cursor.execute(query,{"bank": bankNumber})
-# lastRow = cursor.fetchone()
+ return TestSuceeded()
+
+
+@test
+def row_buffer_is_used_correctly(connection):
+ cursor = connection.cursor()
+ query = """SELECT PhaseName, phases.ID FROM phases INNER JOIN transactions ON phases.transact=transactions.ID WHERE TBank=:bank
+ AND PhaseName NOT IN ('REQ','RESP') ORDER BY PhaseBegin"""
+
+ for bankNumber in range(dramconfig.numberOfBanks):
+ cursor.execute(query,{"bank": bankNumber})
+
+ rowBufferIsClosed = True
+ prechargingPhases = set(['PRE','PRE_ALL','RDA','WRA'])
+ accessingPhases = set(['RD,RDA,WR,WRA,SREF,AUTO_REFRESH'])
+
+ for currentRow in cursor:
+
+ if(currentRow[0] in accessingPhases and rowBufferIsClosed == True):
+ return TestFailed("Phase {0}({1}) acesses a closed rowbuffer".format(currentRow[1], currentRow[0]))
+
+ if(currentRow[0] == 'ACT'):
+ if(rowBufferIsClosed == True):
+ rowBufferIsClosed = False
+ else:
+ return TestFailed("Phase {0}({1}) activates an already activated rowbuffer".format(currentRow[1],currentRow[0]))
+
+ if(currentRow[0] in prechargingPhases):
+ if(rowBufferIsClosed == True and currentRow[0] != 'PRE_ALL'):
+ return TestFailed("Phase {0}({1}) closes an already closed rowbuffer".format(currentRow[1],currentRow[0]))
+ else:
+ rowBufferIsClosed = True
+
+ return TestSuceeded()
+
+
+@test
+def phases_on_bank_are_sequential(connection):
+ cursor = connection.cursor()
+ query = """SELECT PhaseBegin,PhaseEnd,phases.ID,PhaseName FROM phases INNER JOIN transactions on transactions.ID = phases.transact WHERE Tbank=:bank AND phaseName not IN ('REQ','RESP')"""
+
+ for bankNumber in range(dramconfig.numberOfBanks):
+ cursor.execute(query,{"bank": bankNumber})
+ lastRow = cursor.fetchone()
+
+ for currentRow in cursor:
+ if(currentRow[0] < lastRow[1] and not ((currentRow[3]=="RD" and lastRow[3]=="RD")
+ or (currentRow[3]=="PRE" and lastRow[3]=="RD") or (currentRow[3] == "WR" and lastRow[3] == "WR"))):
+
+ return TestFailed("Phases with PhaseIDs {0}({1}) and {2}({3}) should not interleave".format(
+ currentRow[2], currentRow[3],lastRow[2],lastRow[3]))
+ lastRow = currentRow
+
+ return TestSuceeded()
+
+@test
+def phase_lengths_are_correct(connection):
+ query = """SELECT ID,PhaseEnd-PhaseBegin FROM Phases WHERE PhaseName = :command and (PhaseEnd-PhaseBegin)!= :length"""
+ commandLengths = [('RD', dramconfig.tReadLength),
+ ('RDA', dramconfig.tReadLength + dramconfig.tRP),
+ ('WR', dramconfig.tWriteLength),
+ ('WRA', dramconfig.tWriteLength + dramconfig.tRP),
+ ('PRE', dramconfig.tRP),
+ ('ACT', dramconfig.tRCD),
+ ('AUTO_REFRESH', dramconfig.tRFC)]
+
+ for commandLength in commandLengths:
+ command = commandLength[0]
+ length = commandLength[1]
+ cursor = connection.cursor()
+ cursor.execute(query, {"command":command, "length" : length})
+ result = cursor.fetchone()
+ if(result != None):
+ return TestFailed("Phase with ID {0}({1}) has invalid length {2}".format(result[0],command,formatTime(result[1])))
+
+ return TestSuceeded()
+
+
+
+
+#----------- activate checks ---------------------------------------
+
+@test
+def activate_to_activate(connection):
+ """Checks minimal time between two activates (JEDEC 229, P. 27)"""
+ cursor = connection.cursor()
+ cursor.execute("SELECT ID,PhaseBegin from Phases WHERE PhaseName = 'ACT' ORDER BY PhaseBegin")
+ lastRow = cursor.fetchone()
+
+ for currentRow in cursor:
+ timeBetweenActivates = currentRow[1] - lastRow[1];
+ if(timeBetweenActivates < dramconfig.tRRD):
+ return TestFailed("Activates with PhaseIDs {0} and {1} are {2} apart. Minimum time between two activates is {3}".format(currentRow[0], lastRow[0],formatTime(timeBetweenActivates), dramconfig.tRRD))
+ else:
+ lastRow = currentRow
+ return TestSuceeded()
+
+
+@test
+def activate_to_activate_on_same_bank(connection):
+ """Checks minimal time between two activates on the same bank (JEDEC 229, P. 27)"""
+ cursor = connection.cursor()
+ query = "SELECT Phases.ID,PhaseBegin from Phases INNER JOIN Transactions ON Phases.Transact = Transactions.ID WHERE PhaseName = 'ACT' AND TBANK = :bank ORDER BY PhaseBegin"
-# for currentRow in cursor:
-# timeBetweenActivates = currentRow[1] - lastRow[1];
-# if(timeBetweenActivates < dramconfig.tRC):
-# return TestFailed("Activates with PhaseIDs {0} and {1} are {2} apart. Minimum time between two activates is {3}, since they are on the same bank({4})".
-# format(currentRow[0], lastRow[0],formatTime(timeBetweenActivates), dramconfig.tRC))
-# else:
-# lastRow = currentRow
-
-# return TestSuceeded()
-
-# @test
-# def n_activate_window(connection):
-# """Checks n-Activate constraint (JEDEC 229, P. 27)"""
-# cursor = connection.cursor()
-# cursor.execute("SELECT ID,PhaseBegin from Phases WHERE PhaseName = 'ACT' ORDER BY PhaseBegin")
-# activateWindow = []
-
-# for currentRow in cursor:
-# activateWindow.append(currentRow[1])
-# if(len(activateWindow) > dramconfig.nActivateWindow + 1):
-# activateWindow.pop(0)
-# if(activateWindow[dramconfig.nActivateWindow] - activateWindow[0] < dramconfig.tTAW):
-# return TestFailed("Activate with PhaseID {0} and the {1} preceeding activates violate the '{1} activate window' constraint."
-# " No more than {1} activates should be in rolling time window of {2}".format(currentRow[0], dramconfig.nActivateWindow,formatTime(dramconfig.tTAW)))
-# return TestSuceeded()
-
-
-# # ----------- read checks ---------------------------------------
-
-# @test
-# def activate_to_read(connection):
-# """Checks minimal time bewteen activate and following read (JEDEC 229, P. 29)"""
-# cursor = connection.cursor()
-# query = "SELECT Phases.ID,PhaseBegin,PhaseName from Phases INNER JOIN Transactions ON Phases.Transact = Transactions.ID WHERE PhaseName IN ('ACT','RD') AND TBANK = :bank ORDER BY PhaseBegin"
+ for bankNumber in range(dramconfig.numberOfBanks):
+ cursor.execute(query,{"bank": bankNumber})
+ lastRow = cursor.fetchone()
-# for bankNumber in range(dramconfig.numberOfBanks):
+ for currentRow in cursor:
+ timeBetweenActivates = currentRow[1] - lastRow[1];
+ if(timeBetweenActivates < dramconfig.tRC):
+ return TestFailed("Activates with PhaseIDs {0} and {1} are {2} apart. Minimum time between two activates is {3}, since they are on the same bank({4})".
+ format(currentRow[0], lastRow[0],formatTime(timeBetweenActivates), dramconfig.tRC))
+ else:
+ lastRow = currentRow
+
+ return TestSuceeded()
+
+@test
+def n_activate_window(connection):
+ """Checks n-Activate constraint (JEDEC 229, P. 27)"""
+ cursor = connection.cursor()
+ cursor.execute("SELECT ID,PhaseBegin from Phases WHERE PhaseName = 'ACT' ORDER BY PhaseBegin")
+ activateWindow = []
+
+ for currentRow in cursor:
+ activateWindow.append(currentRow[1])
+ if(len(activateWindow) > dramconfig.nActivateWindow + 1):
+ activateWindow.pop(0)
+ if(activateWindow[dramconfig.nActivateWindow] - activateWindow[0] < dramconfig.tTAW):
+ return TestFailed("Activate with PhaseID {0} and the {1} preceeding activates violate the '{1} activate window' constraint."
+ " No more than {1} activates should be in rolling time window of {2}".format(currentRow[0], dramconfig.nActivateWindow,formatTime(dramconfig.tTAW)))
+ return TestSuceeded()
+
+
+# ----------- read/write checks ---------------------------------------
+
+@test
+def read_to_read(connection):
+ """Checks minimal time between two reads(JEDEC 229, P. 29)"""
+ cursor = connection.cursor()
+ cursor.execute("SELECT Phases.ID, PhaseBegin, PhaseName from Phases WHERE PhaseName IN ('RD','RDA') ORDER BY PhaseBegin")
+ lastRow = cursor.fetchone()
+
+ for currentRow in cursor:
+ if(currentRow[1] < lastRow[1] + dramconfig.tReadLength):
+ timeBetweenReads = currentRow[1] - lastRow[1];
+ clocksBetweenReads = round(timeBetweenReads/dramconfig.clk)
+ if(clocksBetweenReads % 2 == 1):
+ return TestFailed("{0} with PhaseID {1} interrupts data acess of {2} {3}. They are {4} clocks ({5}) apart. Numbers of clock between interrupting reads must be even.".
+ format(currentRow[2], currentRow[0], lastRow[2], lastRow[0], clocksBetweenReads, formatTime(timeBetweenReads)))
+ lastRow = currentRow
+
+ return TestSuceeded()
+
+@test
+def write_to_read_and_read_to_write(connection):
+ """Checks minimal time between write and read/read and write (JEDEC 229, P. 33/34)"""
+ cursor = connection.cursor()
+ query = """SELECT Phases.ID,PhaseBegin,PhaseName from Phases INNER JOIN Transactions ON Phases.Transact = Transactions.ID
+ WHERE PhaseName IN ('RD','WR','RDA','WRA') ORDER BY PhaseBegin"""
+
+ cursor.execute(query)
+ lastRow = cursor.fetchone()
+
+ for currentRow in cursor:
+ if(currentRow[2] in ["RD","RDA"] and lastRow[2] in ["WR","WRA"]):
+ writeEndToReadBegin = currentRow[1] - (lastRow[1] + dramconfig.tWriteLength);
+ if(writeEndToReadBegin < dramconfig.tWTR ):
+ return TestFailed("Read with PhaseID {0} starts {1} after end of data access of write {2}. Minimum time between end of write and start of read is {3}".
+ format(currentRow[0],formatTime(writeEndToReadBegin),lastRow[0], formatTime(dramconfig.tWTR )))
+ elif(currentRow[2] in ["WR","WRA"] and lastRow[2] in ["RD","RDA"]):
+ if(currentRow[1] < (lastRow[1]+dramconfig.tReadLength)):
+ return TestFailed("WR with PhaseID {0} starts before end of data acess of read {1}".
+ format(currentRow[0], lastRow[0]))
+ lastRow = currentRow
+
+ return TestSuceeded()
+
+
+@test
+def write_or_read_to_precharge(connection):
+ """Checks minimal time between write/read and precharge (JEDEC 229, P. 37)"""
+ cursor = connection.cursor()
+ query = """SELECT Phases.ID,PhaseBegin,PhaseEnd,PhaseName from Phases INNER JOIN Transactions ON Phases.Transact = Transactions.ID
+ WHERE PhaseName IN ('RD','WR', 'PRE', 'PRE_ALL') AND TBANK = :bank ORDER BY PhaseBegin"""
+
+ minReadStartToPrecharge = dramconfig.burstLength * dramconfig.clk
+ minWriteEndToPreStart = dramconfig.tWR
+
+ for bankNumber in range(dramconfig.numberOfBanks):
-# cursor.execute(query,{"bank": bankNumber})
-# lastRow = cursor.fetchone()
-
-# for currentRow in cursor:
-# if(currentRow[2] == "RD" and lastRow[2] == "ACT"):
-# actToReadTime = currentRow[1] - lastRow[1];
-# if(actToReadTime < dramconfig.tRCD):
-# return TestFailed("Read with PhaseID {0} starts {1} after activate {2}. Minimum activate to read time is {3}".
-# format(currentRow[0],formatTime(actToReadTime),lastRow[0], formatTime(dramconfig.tRCD)))
-# lastRow = currentRow
-
-# return TestSuceeded()
-
-# @test
-# def read_to_read(connection):
-# """Checks minimal time between two reads(JEDEC 229, P. 29)"""
-# cursor = connection.cursor()
-# cursor.execute("SELECT Phases.ID, PhaseBegin, PhaseEnd from Phases WHERE PhaseName = 'RD' ORDER BY PhaseBegin")
-# lastRow = cursor.fetchone()
-
-# for currentRow in cursor:
-# if(currentRow[1] < lastRow[2]):
-# timeBetweenReads = currentRow[1] - lastRow[1];
-# clocksBetweenReads = round(timeBetweenReads/dramconfig.clk)
-# if(clocksBetweenReads % 2 == 1):
-# return TestFailed("Read with PhaseID {0} interrupts read {1}. They are {2} clocks ({3}) apart. Numbers of clock between interrupting reads must be even.".
-# format(currentRow[0], lastRow[0], clocksBetweenReads, formatTime(timeBetweenReads)))
-# lastRow = currentRow
-
-# return TestSuceeded()
-
-# @test
-# def write_to_read(connection):
-# """Checks minimal time between write and following read (JEDEC 229, P. 34)"""
-# cursor = connection.cursor()
-# query = "SELECT Phases.ID,PhaseBegin,PhaseEnd,PhaseName from Phases INNER JOIN Transactions ON Phases.Transact = Transactions.ID WHERE PhaseName IN ('RD','WR') AND TBANK = :bank ORDER BY PhaseBegin"
-
-# for bankNumber in range(dramconfig.numberOfBanks):
-
-# cursor.execute(query,{"bank": bankNumber})
-# lastRow = cursor.fetchone()
-
-# for currentRow in cursor:
-# if(currentRow[3] == "RD" and lastRow[3] == "WR"):
-# writeEndToReadBegin = currentRow[1] - lastRow[2];
-# if(writeEndToReadBegin < dramconfig.tWTR ):
-# return TestFailed("Read with PhaseID {0} starts {1} after end of write {2}. Minimum time between end of write and start of read is {3}".
-# format(currentRow[0],formatTime(writeEndToReadBegin),lastRow[0], formatTime(dramconfig.tWTR )))
-# lastRow = currentRow
-
-# return TestSuceeded()
-
-
-
-
-
-
-
+ cursor.execute(query,{"bank": bankNumber})
+ lastRow = cursor.fetchone()
+ for currentRow in cursor:
+ if(currentRow[3] in ["PRE","PRE_ALL"] and lastRow[3] == "RD"):
+ readStartToPrecharge = currentRow[1] - lastRow[1]
+ if(readStartToPrecharge < minReadStartToPrecharge):
+ return TestFailed("Precharge with PhaseID {0} starts {1} after start of RD {2}. Minimum time between end of read and start of precharge is {3}".
+ format(currentRow[0],formatTime(readStartToPrecharge),lastRow[0], formatTime(minReadStartToPrecharge)))
+
+ elif(currentRow[3] in ["PRE","PRE_ALL"] and lastRow[3] == "WR"):
+ writeEndToPrecharge = currentRow[1] - lastRow[2]
+ if(writeEndToPrecharge < minWriteEndToPreStart):
+ return TestFailed("Precharge with PhaseID {0} starts {1} after end of WR {2}. Minimum time between end of write and start of precharge is {3}".
+ format(currentRow[0],formatTime(writeEndToPrecharge),lastRow[0], formatTime(minWriteEndToPreStart)))
+ lastRow = currentRow
+ return TestSuceeded()
# -------------------------- interface methods --------------------
diff --git a/dram/src/common/DebugManager.cpp b/dram/src/common/DebugManager.cpp
index 8a96c59c..b397232f 100644
--- a/dram/src/common/DebugManager.cpp
+++ b/dram/src/common/DebugManager.cpp
@@ -32,6 +32,24 @@ void DebugManager::printDebugMessage(string message, Sender sender, Importance i
}
}
+void DebugManager::printDebugMessage(std::string message, Sender sender, unsigned int senderNumber,
+ Importance importance)
+{
+ bool show = count(whiteList.begin(), whiteList.end(),
+ pair(sender, importance));
+
+ if (show)
+ {
+ cout << importanceToString(importance);
+ if (printTime)
+ std::cout << " at " << sc_time_stamp();
+ if (printLocation)
+ std::cout << " in " << senderToString(sender) << "number " << senderNumber;
+ cout << ": " << message << endl;
+ }
+}
+
+
void DebugManager::addToWhiteList(Sender sender, Importance importance)
{
whiteList.push_back(pair(sender, importance));
@@ -43,6 +61,7 @@ void DebugManager::addToWhiteList(Sender sender)
addToWhiteList(sender, Importance::Warning);
}
+
string DebugManager::importanceToString(Importance importancy)
{
switch (importancy)
diff --git a/dram/src/common/DebugManager.h b/dram/src/common/DebugManager.h
index 7d708128..d0553c27 100644
--- a/dram/src/common/DebugManager.h
+++ b/dram/src/common/DebugManager.h
@@ -25,6 +25,8 @@ public:
bool printLocation;
void printDebugMessage(std::string message, Sender sender, Importance importance=Importance::Info);
+ void printDebugMessage(std::string message, Sender sender,unsigned int senderNumber, Importance importance=Importance::Info);
+
void addToWhiteList(Sender sender, Importance importance);
void addToWhiteList(Sender sender);
diff --git a/dram/src/core/Controller.cpp b/dram/src/core/Controller.cpp
index 7107c97b..d4ad0f10 100644
--- a/dram/src/core/Controller.cpp
+++ b/dram/src/core/Controller.cpp
@@ -104,6 +104,8 @@ bool Controller::isBusy(sc_time currentTime, Bank bank)
void Controller::send(const CommandSchedule& schedule, tlm::tlm_generic_payload& payload) const
{
+
+
for (const ScheduledCommand& cmd : schedule.getScheduledCommands())
{
wrapper.send(cmd, payload);
diff --git a/dram/src/core/Controller.h b/dram/src/core/Controller.h
index 8d40a324..2d437df0 100644
--- a/dram/src/core/Controller.h
+++ b/dram/src/core/Controller.h
@@ -31,8 +31,6 @@ public:
bool isBusy(sc_time currentTime, Bank bank);
void scheduleRefresh(tlm::tlm_generic_payload& payload, sc_time time);
-
- const ICommandChecker& getChecker(Command command) const;
const BankStates& getBankStates(){return state.bankStates;}
void saveState();
diff --git a/dram/src/core/ControllerState.cpp b/dram/src/core/ControllerState.cpp
index e9e96522..1786b419 100644
--- a/dram/src/core/ControllerState.cpp
+++ b/dram/src/core/ControllerState.cpp
@@ -66,10 +66,9 @@ void ControllerState::change(const ScheduledCommand& scheduledCommand)
break;
case Command::Activate:
bankStates.openRowInRowBuffer(scheduledCommand.getBank(), scheduledCommand.getRow());
- nActivateWindow.put(scheduledCommand.getStart());
- activates.blockSlots(scheduledCommand.getStart() - config->Timings.tRRD,
- scheduledCommand.getStart() + config->Timings.tRRD, true);
+ lastActivates.emplace(scheduledCommand.getStart());
break;
+
case Command::Precharge:
bankStates.closeRowBuffer(scheduledCommand.getBank());
break;
@@ -85,9 +84,8 @@ void ControllerState::change(const ScheduledCommand& scheduledCommand)
void ControllerState::cleanUp(sc_time time)
{
bus.cleanUpSlots(time);
- activates.cleanUpSlots(time);
-
- lastDataStrobeCommands.remove_if([&](ScheduledCommand command){return command.getEnd() < time;});
+ lastDataStrobeCommands.remove_if([&](ScheduledCommand command){return command.getEnd() < time - config->Timings.tStrobeHistory;});
+ lastActivates.erase(lastActivates.begin(), lastActivates.lower_bound(time - config->Timings.tActHistory));
}
} /* namespace controller */
diff --git a/dram/src/core/ControllerState.h b/dram/src/core/ControllerState.h
index fc4a40df..556bbaec 100644
--- a/dram/src/core/ControllerState.h
+++ b/dram/src/core/ControllerState.h
@@ -24,8 +24,7 @@ class ControllerState
{
public:
ControllerState(Configuration* config) :
- bankStates(config->numberOfBanks), nActivateWindow(config->nActivate), bus(
- config->Timings.clk), activates(config->Timings.clk), config(config)
+ bankStates(config->numberOfBanks), bus(config->Timings.clk), config(config)
{
}
virtual ~ControllerState()
@@ -42,11 +41,10 @@ public:
BankStates bankStates;
//used by the various checkers
- RingBuffer nActivateWindow;
std::map > lastCommandsOnBus;
Slots bus;
- Slots activates;
std::list lastDataStrobeCommands;
+ std::set lastActivates;
private:
Configuration* config;
diff --git a/dram/src/core/TimingConfiguration.h b/dram/src/core/TimingConfiguration.h
index 2488aa6f..440e42b5 100644
--- a/dram/src/core/TimingConfiguration.h
+++ b/dram/src/core/TimingConfiguration.h
@@ -29,7 +29,7 @@ struct TimingConfiguration
for (unsigned int i = 0; i < numberOfBanks; ++i)
{
- sc_time tRFC = 21*clk;
+ sc_time tRFC = clkAlign(sc_time(130,SC_NS),clk);
//sc_time tREFI = 100*clk;
sc_time tREFI = sc_time(15.6, SC_US); //TODO align
//tREFI = sc_time(301268, SC_NS);
@@ -47,9 +47,11 @@ struct TimingConfiguration
tRL = 3*clk; //read latency (read command start to data strobe)
tWL = 1*clk; //write latency
tTAW = clkAlign(sc_time(50,SC_NS), clk); //two activate window
- tRR = 2*clk; //min read to read on same rank
- tWW = 1*clk; //min write to write on same rank
tWTR = 3*clk;//write to read
+ tWR = 2*clk; //write recovery (write to precharge)
+
+ tActHistory = tTAW;
+ tStrobeHistory = tWTR;
}
sc_time clk;
@@ -61,10 +63,10 @@ struct TimingConfiguration
sc_time tTAW;
sc_time tRL;
sc_time tWL;
+ sc_time tWR;
sc_time tWTR;
- sc_time tRR;
- sc_time tWW;
+ sc_time tActHistory, tStrobeHistory;
std::vector refreshTimings;
diff --git a/dram/src/core/refresh/RefreshManager.cpp b/dram/src/core/refresh/RefreshManager.cpp
index 57bc5814..98e486d5 100644
--- a/dram/src/core/refresh/RefreshManager.cpp
+++ b/dram/src/core/refresh/RefreshManager.cpp
@@ -40,6 +40,7 @@ void RefreshManager::scheduleRefresh(tlm::tlm_generic_payload& payload, sc_time
ScheduledCommand precharge(Command::PrechargeAll, time,
controller.config.Timings.tRP, DramExtension::getExtension(refreshPayloads.at(0)));
+ controller.commandChecker.at(Command::PrechargeAll)->delayToSatisfyConstraints(precharge);
nextRefresh.setStart(precharge.getEnd());
controller.state.change(precharge);
diff --git a/dram/src/core/refresh/RefreshManagerBankwise.cpp b/dram/src/core/refresh/RefreshManagerBankwise.cpp
index a70660d6..9a6f4a61 100644
--- a/dram/src/core/refresh/RefreshManagerBankwise.cpp
+++ b/dram/src/core/refresh/RefreshManagerBankwise.cpp
@@ -79,8 +79,7 @@ void RefreshManagerBankwise::RefreshManagerForBank::scheduleRefresh(sc_time time
if (controller.state.bankStates.rowBufferIsOpen(bank))
{
ScheduledCommand precharge(Command::Precharge, time, controller.config.Timings.tRP, DramExtension::getExtension(refreshPayload));
-
- controller.state.bus.moveCommandToNextFreeSlot(precharge);
+ controller.commandChecker.at(Command::Precharge)->delayToSatisfyConstraints(precharge);
nextRefresh.setStart(precharge.getEnd());
controller.state.change(precharge);
diff --git a/dram/src/core/scheduling/checker/ActivateChecker.cpp b/dram/src/core/scheduling/checker/ActivateChecker.cpp
index 991a090d..8a792b8c 100644
--- a/dram/src/core/scheduling/checker/ActivateChecker.cpp
+++ b/dram/src/core/scheduling/checker/ActivateChecker.cpp
@@ -5,8 +5,8 @@
* Author: jonny
*/
-#include