|
|
|
|
@@ -1,56 +1,154 @@
|
|
|
|
|
import sys
|
|
|
|
|
import sqlite3
|
|
|
|
|
import math
|
|
|
|
|
import os
|
|
|
|
|
import xml.etree.ElementTree as ET
|
|
|
|
|
|
|
|
|
|
class DramConfig(object):
|
|
|
|
|
"""Holds the timing constraints in the standard and the configuration of the DRAM"""
|
|
|
|
|
|
|
|
|
|
unitOfTime = "ns"
|
|
|
|
|
nActivateWindow = 0
|
|
|
|
|
clk = numberOfBanks = 0
|
|
|
|
|
tRP = tRAS = tRC = tRRD = tRCD = tTAW = tRL = tWL = tWTR = tRFC = tWR = 0
|
|
|
|
|
tReadLength = tWriteLength = 0
|
|
|
|
|
def getPathToConfigs():
|
|
|
|
|
return os.path.dirname(__file__).replace("/scripts","/configs")
|
|
|
|
|
|
|
|
|
|
def getValueFromConfigXML(root, id):
|
|
|
|
|
return root.findall(".//parameter[@id='{0}']".format(id))[0].attrib['value']
|
|
|
|
|
|
|
|
|
|
def getMemconfig(connection):
|
|
|
|
|
cursor = connection.cursor()
|
|
|
|
|
cursor.execute("SELECT Memconfig FROM GeneralInfo")
|
|
|
|
|
result = cursor.fetchone()
|
|
|
|
|
memconfig = getPathToConfigs() + "/memconfigs/" + result[0]
|
|
|
|
|
return ET.parse(memconfig)
|
|
|
|
|
|
|
|
|
|
def getMemspec(connection):
|
|
|
|
|
cursor = connection.cursor()
|
|
|
|
|
cursor.execute("SELECT Memspec FROM GeneralInfo")
|
|
|
|
|
result = cursor.fetchone()
|
|
|
|
|
memspec = getPathToConfigs() + "/memspecs/" + result[0]
|
|
|
|
|
return ET.parse(memspec)
|
|
|
|
|
|
|
|
|
|
def getClock(connection):
|
|
|
|
|
cursor = connection.cursor()
|
|
|
|
|
cursor.execute("SELECT clk, UnitOfTime FROM GeneralInfo")
|
|
|
|
|
result = cursor.fetchone()
|
|
|
|
|
return (result[0],result[1])
|
|
|
|
|
|
|
|
|
|
class DramConfig(object):
|
|
|
|
|
memoryType = ""
|
|
|
|
|
bankwiseRefresh = False
|
|
|
|
|
bankwisePowerdown = False
|
|
|
|
|
clk = 0
|
|
|
|
|
unitOfTime = ""
|
|
|
|
|
dataRate = 0
|
|
|
|
|
nActivateWindow = numberOfBanks = 0
|
|
|
|
|
|
|
|
|
|
clk = 0
|
|
|
|
|
tRP = 0 #precharge-time (pre -> act same bank)
|
|
|
|
|
tRAS = 0 #active-time (act -> pre same bank)
|
|
|
|
|
tRC = 0 #RAS-cycle-time (min time bw 2 succesive ACT to same bank)
|
|
|
|
|
tCCD_S = 0 #TODO: relevant? max(bl, tCCD)
|
|
|
|
|
tCCD_L = 0
|
|
|
|
|
tRTP = 0 #Read to precharge
|
|
|
|
|
tRRD_S = 0 #min time bw 2 succesive ACT to different banks (different bank group)
|
|
|
|
|
tRRD_L = 0 #.. (same bank group)
|
|
|
|
|
tRCD = 0 #act -> read/write
|
|
|
|
|
tNAW = 0 #n activate window
|
|
|
|
|
tRL = 0 #read latency (read command start to data strobe)
|
|
|
|
|
tWL = 0 #write latency
|
|
|
|
|
tWR = 0 #write recovery (write to precharge)
|
|
|
|
|
tWTR_S = 0 #write to read (different bank group)
|
|
|
|
|
tWTR_L = 0 #.. (same bank group)
|
|
|
|
|
tCKESR = 0 #min time in sref
|
|
|
|
|
tCKE = 0 #min time in pdna or pdnp
|
|
|
|
|
tXP = 0 #min delay to row access command after pdnpx pdnax
|
|
|
|
|
tXPDLL = 0 #min delay to row access command after pdnpx pdnax for dll commands
|
|
|
|
|
tXSR = 0 #min delay to row access command after srefx
|
|
|
|
|
tXSRDLL = 0 #min delay to row access command after srefx for dll commands
|
|
|
|
|
tAL = 0 #additive delay (delayed execution in dram)
|
|
|
|
|
tRFC = 0 #min ref->act delay
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def readConfigFromFiles(self, connection):
|
|
|
|
|
print("parsing stuff and stuff")
|
|
|
|
|
memspec = getMemspec(connection)
|
|
|
|
|
|
|
|
|
|
bankwisePowerdown = bankwiseRefresh = getValueFromConfigXML(getMemconfig(connection), "bankwiseLogic")
|
|
|
|
|
clk = getClock(connection)
|
|
|
|
|
self.clk = clk[0]
|
|
|
|
|
self.unitOfTime = clk[1].lower()
|
|
|
|
|
|
|
|
|
|
self.numberOfBanks = getValueFromConfigXML(memspec, "nbrOfBanks")
|
|
|
|
|
self.burstLength = getValueFromConfigXML(memspec, "burstLength")
|
|
|
|
|
self.memoryType = getValueFromConfigXML(memspec, "memoryType")
|
|
|
|
|
self.dataRate = getValueFromConfigXML(memspec, "dataRate")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(self.memoryType == "WIDEIO_SDR"):
|
|
|
|
|
self.nActivateWindow = 2;
|
|
|
|
|
self.tRP = self.clk * getValueFromConfigXML(memspec, "RP")
|
|
|
|
|
self.tRAS = self.clk * getValueFromConfigXML(memspec, "RAS")
|
|
|
|
|
self.tRC = self.clk * getValueFromConfigXML(memspec, "RC")
|
|
|
|
|
self.tRRD_S = self.clk * getValueFromConfigXML(memspec, "RRD")
|
|
|
|
|
self.tRRD_L = self.tRRD_S
|
|
|
|
|
self.tCCD_S = self.clk * getValueFromConfigXML(memspec, "CCD")
|
|
|
|
|
self.tCCD_L = self.tCCD_S
|
|
|
|
|
self.tRCD = self.clk * getValueFromConfigXML(memspec, "RCD")
|
|
|
|
|
self.tNAW = self.clk * getValueFromConfigXML(memspec, "TAW")
|
|
|
|
|
self.tRL = self.clk * getValueFromConfigXML(memspec, "RL")
|
|
|
|
|
self.tWL = self.clk * getValueFromConfigXML(memspec, "WL")
|
|
|
|
|
self.tWR = self.clk * getValueFromConfigXML(memspec, "WR")
|
|
|
|
|
self.tWTR_S = self.clk * getValueFromConfigXML(memspec, "WTR")
|
|
|
|
|
self.tWTR_L = self.tWTR_S
|
|
|
|
|
self.tRTP = 0
|
|
|
|
|
self.tCKESR = self.clk * getValueFromConfigXML(memspec, "CKESR")
|
|
|
|
|
self.tCKE = self.clk * getValueFromConfigXML(memspec, "CKE")
|
|
|
|
|
self.tXP = self.clk * getValueFromConfigXML(memspec, "XP")
|
|
|
|
|
self.tXPDLL = self.tXP
|
|
|
|
|
self.tXSR = self.clk * getValueFromConfigXML(memspec, "XS")
|
|
|
|
|
self.tXSRDLL = self.tXSR
|
|
|
|
|
self.tAL = self.clk * getValueFromConfigXML(memspec, "AL")
|
|
|
|
|
self.tRFC = self.clk * getValueFromConfigXML(memspec, "RFC")
|
|
|
|
|
|
|
|
|
|
elif(self. memoryType == "DDR4"):
|
|
|
|
|
self.tRP = clk * getValueFromConfigXML(memspec, "RP");
|
|
|
|
|
self.tRAS = clk * getValueFromConfigXML(memspec, "RAS");
|
|
|
|
|
self.tRC = clk * getValueFromConfigXML(memspec, "RC");
|
|
|
|
|
self.tRTP = clk * getValueFromConfigXML(memspec, "RTP");
|
|
|
|
|
self.tRRD_S = clk * getValueFromConfigXML(memspec, "RRD_S");
|
|
|
|
|
self.tRRD_L = clk * getValueFromConfigXML(memspec, "RRD_L");
|
|
|
|
|
self.tCCD_S = clk * getValueFromConfigXML(memspec, "CCD_S");
|
|
|
|
|
self.tCCD_L = clk * getValueFromConfigXML(memspec, "CCD_L");
|
|
|
|
|
self.tRCD = clk * getValueFromConfigXML(memspec, "RCD");
|
|
|
|
|
self.tNAW = clk * getValueFromConfigXML(memspec, "FAW");
|
|
|
|
|
self.tRL = clk * getValueFromConfigXML(memspec, "RL");
|
|
|
|
|
self.tWL = clk * getValueFromConfigXML(memspec, "WL");
|
|
|
|
|
self.tWR = clk * getValueFromConfigXML(memspec, "WR");
|
|
|
|
|
self.tWTR_S = clk * getValueFromConfigXML(memspec, "WTR_S");
|
|
|
|
|
self.tWTR_L = clk * getValueFromConfigXML(memspec, "WTR_L");
|
|
|
|
|
self.tCKESR = clk * getValueFromConfigXML(memspec, "CKESR");
|
|
|
|
|
self.tCKE = clk * getValueFromConfigXML(memspec, "CKE");
|
|
|
|
|
self.tXP = clk * getValueFromConfigXML(memspec, "XP");
|
|
|
|
|
self.tXPDLL = clk * getValueFromConfigXML(memspec, "XPDLL");
|
|
|
|
|
self.tXSR = clk * getValueFromConfigXML(memspec, "XS");
|
|
|
|
|
self.tXSRDLL = clk * getValueFromConfigXML(memspec, "XSDLL");
|
|
|
|
|
self.tAL = clk * getValueFromConfigXML(memspec, "AL");
|
|
|
|
|
self.tRFC = clk * getValueFromConfigXML(memspec, "RFC");
|
|
|
|
|
else:
|
|
|
|
|
raise Exception("MemoryType not supported yet. Insert some coins and try again")
|
|
|
|
|
|
|
|
|
|
def clkAlign(self, value):
|
|
|
|
|
return math.ceil(1.0*value/self.clk)*self.clk
|
|
|
|
|
|
|
|
|
|
def parseFromXml(self):
|
|
|
|
|
self.clk = 6
|
|
|
|
|
self.numberOfBanks = 8
|
|
|
|
|
self.nActivateWindow = 2
|
|
|
|
|
self.burstLength = 2
|
|
|
|
|
|
|
|
|
|
self.tRP = 3*self.clk
|
|
|
|
|
self.tRAS = 6*self.clk
|
|
|
|
|
self.tRRD = 2*self.clk
|
|
|
|
|
self.tRC = self.tRP + self.tRAS
|
|
|
|
|
self.tRCD = 3*self.clk
|
|
|
|
|
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.tCKESR = self.clkAlign(max(3*self.clk, 15))
|
|
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self.parseFromXml()
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
dramconfig = DramConfig()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def calculateReadLength(burstLength):
|
|
|
|
|
return dramconfig.tRL + burstLength * dramconfig.clk
|
|
|
|
|
|
|
|
|
|
def calculateWriteLength(burstLength):
|
|
|
|
|
return dramconfig.tWL + burstLength * dramconfig.clk
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ----------- test utils ---------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tests = []
|
|
|
|
|
|
|
|
|
|
def test(function):
|
|
|
|
|
@@ -73,12 +171,11 @@ def TestFailed(message):
|
|
|
|
|
def formatTime(time):
|
|
|
|
|
return ('{0} {1}'.format(time, dramconfig.unitOfTime))
|
|
|
|
|
|
|
|
|
|
# ----------- command bus checks ---------------------------------------
|
|
|
|
|
# ----------- checks ---------------------------------------
|
|
|
|
|
|
|
|
|
|
@test
|
|
|
|
|
def commands_are_clockaligned(connection):
|
|
|
|
|
"""Checks that all commands on the command bus are aligned to the system clock"""
|
|
|
|
|
passedTest = True
|
|
|
|
|
cursor = connection.cursor()
|
|
|
|
|
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})
|
|
|
|
|
@@ -88,272 +185,272 @@ def commands_are_clockaligned(connection):
|
|
|
|
|
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()
|
|
|
|
|
# @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()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if dramconfig.bankwisePowerdown and dramconfig.bankwiseRefresh:
|
|
|
|
|
excludedPhases = "('REQ','RESP','PRE_ALL')"
|
|
|
|
|
elif (not dramconfig.bankwisePowerdown and dramconfig.bankwiseRefresh):
|
|
|
|
|
excludedPhases = "('REQ','RESP','PRE_ALL','PDNA','PDNP','SREF')"
|
|
|
|
|
elif dramconfig.bankwisePowerdown and not dramconfig.bankwiseRefresh:
|
|
|
|
|
excludedPhases = "('REQ','RESP','PRE_ALL','AUTO_REFRESH')"
|
|
|
|
|
else:
|
|
|
|
|
excludedPhases = "('REQ','RESP','PRE_ALL','PDNA','PDNP','SREF','AUTO_REFRESH')"
|
|
|
|
|
# if dramconfig.bankwisePowerdown and dramconfig.bankwiseRefresh:
|
|
|
|
|
# excludedPhases = "('REQ','RESP','PRE_ALL')"
|
|
|
|
|
# elif (not dramconfig.bankwisePowerdown and dramconfig.bankwiseRefresh):
|
|
|
|
|
# excludedPhases = "('REQ','RESP','PRE_ALL','PDNA','PDNP','SREF')"
|
|
|
|
|
# elif dramconfig.bankwisePowerdown and not dramconfig.bankwiseRefresh:
|
|
|
|
|
# excludedPhases = "('REQ','RESP','PRE_ALL','AUTO_REFRESH')"
|
|
|
|
|
# else:
|
|
|
|
|
# excludedPhases = "('REQ','RESP','PRE_ALL','PDNA','PDNP','SREF','AUTO_REFRESH')"
|
|
|
|
|
|
|
|
|
|
query = """SELECT PhaseBegin,count FROM (SELECT phaseBegin,count(phasebegin) AS count
|
|
|
|
|
FROM Phases WHERE PhaseName NOT IN """ + excludedPhases + """ AND phasebegin>0 GROUP BY phaseBegin) WHERE count>1"""
|
|
|
|
|
cursor.execute(query)
|
|
|
|
|
result = cursor.fetchone()
|
|
|
|
|
if(result != None):
|
|
|
|
|
return TestFailed("Slot on commandbus at time {0} is used multiple times".format(formatTime(result[0])))
|
|
|
|
|
# query = """SELECT PhaseBegin,count FROM (SELECT phaseBegin,count(phasebegin) AS count
|
|
|
|
|
# FROM Phases WHERE PhaseName NOT IN """ + excludedPhases + """ AND phasebegin>0 GROUP BY phaseBegin) WHERE count>1"""
|
|
|
|
|
# cursor.execute(query)
|
|
|
|
|
# result = cursor.fetchone()
|
|
|
|
|
# if(result != None):
|
|
|
|
|
# return TestFailed("Slot on commandbus at time {0} is used multiple times".format(formatTime(result[0])))
|
|
|
|
|
|
|
|
|
|
return TestSuceeded()
|
|
|
|
|
# return TestSuceeded()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@test
|
|
|
|
|
def command_sequences_are_valid(connection):
|
|
|
|
|
cursor = connection.cursor()
|
|
|
|
|
cursor.execute("SELECT group_concat(phaseName),transact FROM phases GROUP BY transact")
|
|
|
|
|
# @test
|
|
|
|
|
# def command_sequences_are_valid(connection):
|
|
|
|
|
# cursor = connection.cursor()
|
|
|
|
|
# cursor.execute("SELECT group_concat(phaseName),transact FROM phases GROUP BY transact")
|
|
|
|
|
|
|
|
|
|
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'
|
|
|
|
|
])
|
|
|
|
|
# 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'
|
|
|
|
|
# ])
|
|
|
|
|
|
|
|
|
|
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 currentRow in cursor:
|
|
|
|
|
# commandSequence = currentRow[0]
|
|
|
|
|
# if(commandSequence not in validSequences):
|
|
|
|
|
# return TestFailed("Transaction {0} generated invalid command sequence {1}".format(currentRow[1], commandSequence))
|
|
|
|
|
|
|
|
|
|
return TestSuceeded()
|
|
|
|
|
# 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"""
|
|
|
|
|
# @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})
|
|
|
|
|
# for bankNumber in range(dramconfig.numberOfBanks):
|
|
|
|
|
# cursor.execute(query,{"bank": bankNumber})
|
|
|
|
|
|
|
|
|
|
rowBufferIsClosed = True
|
|
|
|
|
#phases that precharge the bank
|
|
|
|
|
prechargingPhases = set(['PRE','PRE_ALL','RDA','WRA'])
|
|
|
|
|
#phases that require the bank to be precharged
|
|
|
|
|
accessingPhases = set(['RD,RDA,WR,WRA,SREF,AUTO_REFRESH'])
|
|
|
|
|
# rowBufferIsClosed = True
|
|
|
|
|
# #phases that precharge the bank
|
|
|
|
|
# prechargingPhases = set(['PRE','PRE_ALL','RDA','WRA'])
|
|
|
|
|
# #phases that require the bank to be precharged
|
|
|
|
|
# accessingPhases = set(['RD,RDA,WR,WRA,SREF,AUTO_REFRESH'])
|
|
|
|
|
|
|
|
|
|
for currentRow in cursor:
|
|
|
|
|
# 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] 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] == '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
|
|
|
|
|
# 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()
|
|
|
|
|
# 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')"""
|
|
|
|
|
# @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 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"))):
|
|
|
|
|
# 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 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()
|
|
|
|
|
# return TestSuceeded()
|
|
|
|
|
|
|
|
|
|
#@test
|
|
|
|
|
def phase_lengths_are_correct(connection):
|
|
|
|
|
query = """SELECT phases.ID,PhaseName, PhaseEnd-PhaseBegin,Burstlength FROM Phases INNER JOIN transactions ON transactions.ID = phases.transact """
|
|
|
|
|
cursor = connection.cursor()
|
|
|
|
|
cursor.execute(query)
|
|
|
|
|
# #@test
|
|
|
|
|
# def phase_lengths_are_correct(connection):
|
|
|
|
|
# query = """SELECT phases.ID,PhaseName, PhaseEnd-PhaseBegin,Burstlength FROM Phases INNER JOIN transactions ON transactions.ID = phases.transact """
|
|
|
|
|
# cursor = connection.cursor()
|
|
|
|
|
# cursor.execute(query)
|
|
|
|
|
|
|
|
|
|
for currentRow in cursor:
|
|
|
|
|
command = currentRow[1]
|
|
|
|
|
commandLength = currentRow[2]
|
|
|
|
|
burstlength = currentRow[3]
|
|
|
|
|
if(command == "RD" and commandLength != calculateReadLength(burstlength) or
|
|
|
|
|
command == "WR" and commandLength != calculateWriteLength(burstLength) or
|
|
|
|
|
command == "RDA" and commandLength != calculateReadLength(burstlength)+dramconfig.tRP or
|
|
|
|
|
command == "WRA" and commandLength != calculateReadLength(burstlength)+dramconfig.tRP or
|
|
|
|
|
(command == "PRE" or command=="PRE_ALL") and commandLength != dramconfig.tRP or
|
|
|
|
|
command == "AUTO_REFRESH" and commandLength != dramconfig.tRFC):
|
|
|
|
|
return TestFailed("Phase with ID {0}({1}) has invalid length of {2}".format(currentRow[0],command,formatTime(commandLength)))
|
|
|
|
|
return TestSuceeded()
|
|
|
|
|
# for currentRow in cursor:
|
|
|
|
|
# command = currentRow[1]
|
|
|
|
|
# commandLength = currentRow[2]
|
|
|
|
|
# burstlength = currentRow[3]
|
|
|
|
|
# if(command == "RD" and commandLength != calculateReadLength(burstlength) or
|
|
|
|
|
# command == "WR" and commandLength != calculateWriteLength(burstLength) or
|
|
|
|
|
# command == "RDA" and commandLength != calculateReadLength(burstlength)+dramconfig.tRP or
|
|
|
|
|
# command == "WRA" and commandLength != calculateReadLength(burstlength)+dramconfig.tRP or
|
|
|
|
|
# (command == "PRE" or command=="PRE_ALL") and commandLength != dramconfig.tRP or
|
|
|
|
|
# command == "AUTO_REFRESH" and commandLength != dramconfig.tRFC):
|
|
|
|
|
# return TestFailed("Phase with ID {0}({1}) has invalid length of {2}".format(currentRow[0],command,formatTime(commandLength)))
|
|
|
|
|
# return TestSuceeded()
|
|
|
|
|
|
|
|
|
|
#----------- activate checks ---------------------------------------
|
|
|
|
|
# #----------- 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()
|
|
|
|
|
# @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()
|
|
|
|
|
# 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"
|
|
|
|
|
# @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 bankNumber in range(dramconfig.numberOfBanks):
|
|
|
|
|
cursor.execute(query,{"bank": bankNumber})
|
|
|
|
|
lastRow = cursor.fetchone()
|
|
|
|
|
# for bankNumber in range(dramconfig.numberOfBanks):
|
|
|
|
|
# cursor.execute(query,{"bank": bankNumber})
|
|
|
|
|
# lastRow = cursor.fetchone()
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
# 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()
|
|
|
|
|
# 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 = []
|
|
|
|
|
# @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()
|
|
|
|
|
# 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 ---------------------------------------
|
|
|
|
|
# # ----------- 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()
|
|
|
|
|
# @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
|
|
|
|
|
# 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()
|
|
|
|
|
# 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"""
|
|
|
|
|
# @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()
|
|
|
|
|
# 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
|
|
|
|
|
# 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()
|
|
|
|
|
# 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"""
|
|
|
|
|
# @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
|
|
|
|
|
# minReadStartToPrecharge = dramconfig.burstLength * dramconfig.clk
|
|
|
|
|
# minWriteEndToPreStart = dramconfig.tWR
|
|
|
|
|
|
|
|
|
|
for bankNumber in range(dramconfig.numberOfBanks):
|
|
|
|
|
# for bankNumber in range(dramconfig.numberOfBanks):
|
|
|
|
|
|
|
|
|
|
cursor.execute(query,{"bank": bankNumber})
|
|
|
|
|
lastRow = cursor.fetchone()
|
|
|
|
|
# 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)))
|
|
|
|
|
# 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)))
|
|
|
|
|
# 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()
|
|
|
|
|
# lastRow = currentRow
|
|
|
|
|
# return TestSuceeded()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@test
|
|
|
|
|
def sref_active_for_minimal_time(connection):
|
|
|
|
|
"""Checks if SREF is active for at least a minimal time (JEDEC 229, P. 41)"""
|
|
|
|
|
cursor = connection.cursor()
|
|
|
|
|
cursor.execute("SELECT ID, PhaseEnd-PhaseBegin FROM Phases WHERE PhaseName = 'SREF'")
|
|
|
|
|
for currentRow in cursor:
|
|
|
|
|
if(currentRow[1] < dramconfig.tCKESR):
|
|
|
|
|
return TestFailed("SREF with ID {0} is {1} long. Minimal time in SREF is {2}".format(currentRow[0], formatTime(currentRow[1]), dramconfig.tCKESR))
|
|
|
|
|
return TestSuceeded()
|
|
|
|
|
# @test
|
|
|
|
|
# def sref_active_for_minimal_time(connection):
|
|
|
|
|
# """Checks if SREF is active for at least a minimal time (JEDEC 229, P. 41)"""
|
|
|
|
|
# cursor = connection.cursor()
|
|
|
|
|
# cursor.execute("SELECT ID, PhaseEnd-PhaseBegin FROM Phases WHERE PhaseName = 'SREF'")
|
|
|
|
|
# for currentRow in cursor:
|
|
|
|
|
# if(currentRow[1] < dramconfig.tCKESR):
|
|
|
|
|
# return TestFailed("SREF with ID {0} is {1} long. Minimal time in SREF is {2}".format(currentRow[0], formatTime(currentRow[1]), dramconfig.tCKESR))
|
|
|
|
|
# return TestSuceeded()
|
|
|
|
|
# -------------------------- interface methods --------------------
|
|
|
|
|
|
|
|
|
|
def runTests(pathToTrace):
|
|
|
|
|
connection = sqlite3.connect(pathToTrace)
|
|
|
|
|
dramconfig.readConfigFromFiles(connection)
|
|
|
|
|
|
|
|
|
|
testResults = []
|
|
|
|
|
numberOfFailedTest = 0
|
|
|
|
|
|