Files
DRAMSys/dram/resources/scripts/tests.py
2014-05-05 23:24:36 +02:00

618 lines
24 KiB
Python

import sys
import traceback
import sqlite3
import os
import xml.etree.ElementTree as ET
def getPathToConfigs():
return os.path.dirname(os.path.abspath(__file__).replace("/scripts","/configs"))
def getValueFromConfigXML(root, id):
return root.findall(".//parameter[@id='{0}']".format(id))[0].attrib['value']
def getIntValueFromConfigXML(root, id):
return int(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 = ""
bankwiseLogic = 0
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 dram configuration")
memspec = getMemspec(connection)
clkWithUnit = getClock(connection)
self.clk = clkWithUnit[0]
self.unitOfTime = clkWithUnit[1].lower()
self.bankwiseLogic = getIntValueFromConfigXML(getMemconfig(connection), "bankwiseLogic")
self.numberOfBanks = getIntValueFromConfigXML(memspec, "nbrOfBanks")
self.burstLength = getIntValueFromConfigXML(memspec, "burstLength")
self.memoryType = getValueFromConfigXML(memspec, "memoryType")
self.dataRate = getIntValueFromConfigXML(memspec, "dataRate")
if(self.memoryType == "WIDEIO_SDR"):
self.nActivateWindow = 2;
self.tRP = self.clk * getIntValueFromConfigXML(memspec, "RP")
self.tRAS = self.clk * getIntValueFromConfigXML(memspec, "RAS")
self.tRC = self.clk * getIntValueFromConfigXML(memspec, "RC")
self.tRRD_S = self.clk * getIntValueFromConfigXML(memspec, "RRD")
self.tRRD_L = self.tRRD_S
self.tCCD_S = self.clk * getIntValueFromConfigXML(memspec, "CCD")
self.tCCD_L = self.tCCD_S
self.tRCD = self.clk * getIntValueFromConfigXML(memspec, "RCD")
self.tNAW = self.clk * getIntValueFromConfigXML(memspec, "TAW")
self.tRL = self.clk * getIntValueFromConfigXML(memspec, "RL")
self.tWL = self.clk * getIntValueFromConfigXML(memspec, "WL")
self.tWR = self.clk * getIntValueFromConfigXML(memspec, "WR")
self.tWTR_S = self.clk * getIntValueFromConfigXML(memspec, "WTR")
self.tWTR_L = self.tWTR_S
self.tRTP = self.clk * getIntValueFromConfigXML(memspec, "RTP");
self.tCKESR = self.clk * getIntValueFromConfigXML(memspec, "CKESR")
self.tCKE = self.clk * getIntValueFromConfigXML(memspec, "CKE")
self.tXP = self.clk * getIntValueFromConfigXML(memspec, "XP")
self.tXPDLL = self.tXP
self.tXSR = self.clk * getIntValueFromConfigXML(memspec, "XS")
self.tXSRDLL = self.tXSR
self.tAL = self.clk * getIntValueFromConfigXML(memspec, "AL")
self.tRFC = self.clk * getIntValueFromConfigXML(memspec, "RFC")
elif(self. memoryType == "DDR4"):
self.nActivateWindow = 4;
self.tRP = self.clk * getIntValueFromConfigXML(memspec, "RP");
self.tRAS = self.clk * getIntValueFromConfigXML(memspec, "RAS");
self.tRC = self.clk * getIntValueFromConfigXML(memspec, "RC");
self.tRTP = self.clk * getIntValueFromConfigXML(memspec, "RTP");
self.tRRD_S = self.clk * getIntValueFromConfigXML(memspec, "RRD_S");
self.tRRD_L = self.clk * getIntValueFromConfigXML(memspec, "RRD_L");
self.tCCD_S = self.clk * getIntValueFromConfigXML(memspec, "CCD_S");
self.tCCD_L = self.clk * getIntValueFromConfigXML(memspec, "CCD_L");
self.tRCD = self.clk * getIntValueFromConfigXML(memspec, "RCD");
self.tNAW = self.clk * getIntValueFromConfigXML(memspec, "FAW");
self.tRL = self.clk * getIntValueFromConfigXML(memspec, "RL");
self.tWL = self.clk * getIntValueFromConfigXML(memspec, "WL");
self.tWR = self.clk * getIntValueFromConfigXML(memspec, "WR");
self.tWTR_S = self.clk * getIntValueFromConfigXML(memspec, "WTR_S");
self.tWTR_L = self.clk * getIntValueFromConfigXML(memspec, "WTR_L");
self.tCKESR = self.clk * getIntValueFromConfigXML(memspec, "CKESR");
self.tCKE = self.clk * getIntValueFromConfigXML(memspec, "CKE");
self.tXP = self.clk * getIntValueFromConfigXML(memspec, "XP");
self.tXPDLL = self.clk * getIntValueFromConfigXML(memspec, "XPDLL");
self.tXSR = self.clk * getIntValueFromConfigXML(memspec, "XS");
self.tXSRDLL = self.clk * getIntValueFromConfigXML(memspec, "XSDLL");
self.tAL = self.clk * getIntValueFromConfigXML(memspec, "AL");
self.tRFC = self.clk * getIntValueFromConfigXML(memspec, "RFC");
else:
raise Exception("MemoryType not supported yet. Insert a coin into the coin machine and try again")
def clkAlign(self, value):
return math.ceil(1.0*value/self.clk)*self.clk
def getWriteAccessTime(self):
if(self.dataRate == 1):
return self.clk*(self.burstLength - 1)
elif (self.memoryType == "DDR4"):
return self.clk*self.burstLength/self.dataRate
def getReadAccessTime(self):
return self.burstLength/self.dataRate * dramconfig.clk
def __init__(self):
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):
tests.append(function)
return function
class TestResult(object):
passed = True
message = ''
def __init__(self, passed = True, message = ''):
self.passed = passed
self.message = message
def TestSuceeded():
return TestResult()
def TestFailed(message):
return TestResult(False,message);
def formatTime(time):
return ('{0} {1}'.format(time, dramconfig.unitOfTime))
# ----------- checks ---------------------------------------
@test
def commands_are_clockaligned(connection):
"""Checks that all commands on the command bus are aligned to the system clock"""
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": dramconfig.clk})
result = cursor.fetchone()
if(result != None):
return TestFailed("Command with PhaseID {0} starts at {1} and ends at. One of those times. 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()
if dramconfig.bankwiseLogic:
excludedPhases = "('REQ','RESP','PRE_ALL')"
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])))
return TestSuceeded()
@test
def phase_transitions_are_valid(connection):
"""Checks that all transition of two consequtive phases on the same bank are valid"""
cursor = connection.cursor()
validTransitions = {}
if(dramconfig.bankwiseLogic):
validTransitions['PRE'] = set(['ACT', 'AUTO_REFRESH'])
validTransitions['ACT'] = set(['RD', 'RDA', 'WR', 'WRA'])
validTransitions['RD'] = set(['PRE','RD','RDA', 'WR', 'WRA', 'PDNA'])
validTransitions['WR'] = set(['PRE', 'RD','RDA', 'WR', 'WRA', 'PDNA'])
validTransitions['RDA'] = set(['ACT', 'AUTO_REFRESH', 'PDNP'])
validTransitions['WRA'] = set(['ACT', 'AUTO_REFRESH', 'PDNP'])
validTransitions['AUTO_REFRESH'] = set(['ACT', 'PDNP', 'SREF'])
validTransitions['PDNA'] = set(['PRE', 'RD','RDA', 'WR', 'WRA', 'AUTO_REFRESH'])
validTransitions['PDNP'] = set(['ACT', 'AUTO_REFRESH'])
validTransitions['SREF'] = set(['ACT'])
else:
validTransitions['PRE'] = set(['ACT'])
validTransitions['PRE_ALL'] = set(['AUTO_REFRESH'])
validTransitions['ACT'] = set(['RD', 'RDA', 'WR', 'WRA'])
validTransitions['RD'] = set(['PRE', 'PRE_ALL','RD','RDA', 'WR', 'WRA', 'PDNA'])
validTransitions['WR'] = set(['PRE', 'PRE_ALL','RD','RDA', 'WR', 'WRA', 'PDNA'])
validTransitions['RDA'] = set(['PRE_ALL', 'ACT', 'AUTO_REFRESH', 'PDNA', 'PDNP'])
validTransitions['WRA'] = set(['PRE_ALL', 'ACT', 'AUTO_REFRESH', 'PDNA', 'PDNP'])
validTransitions['AUTO_REFRESH'] = set(['PRE_ALL', 'ACT','AUTO_REFRESH', 'PDNA', 'PDNP', 'SREF'])
validTransitions['PDNA'] = set(['PRE','PRE_ALL','ACT', 'RD', 'RDA', 'WR', 'WRA', 'AUTO_REFRESH', 'PDNA', 'PDNP'])
validTransitions['PDNP'] = set(['PRE_ALL', 'ACT', 'AUTO_REFRESH', 'PDNA', 'PDNP'])
validTransitions['SREF'] = set(['PRE_ALL', 'ACT', 'AUTO_REFRESH', 'PDNA', 'PDNP'])
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})
lastRow = cursor.fetchone()
for currentRow in cursor:
currentPhase = currentRow[0]
lastPhase = lastRow[0]
if(currentPhase not in validTransitions[lastPhase]):
return TestFailed("Phase {0}({1}) is not allowed to follow phase {2}({3})".format(currentRow[1],currentPhase,lastRow[1],lastPhase))
lastRow = currentRow
return TestSuceeded()
def timing_constraint(FirstPhase, SecondPhase):
FirstPhaseName = FirstPhase[0]
SecondPhaseName = SecondPhase[0]
if(FirstPhaseName == "PRE" or FirstPhaseName == "PRE_ALL"):
return dramconfig.tRP
elif(FirstPhaseName == "ACT"):
return dramconfig.tRCD
elif(FirstPhaseName == "RD"):
if(SecondPhaseName in ["PRE, PRE_ALL"]):
return dramconfig.tRTP
elif(SecondPhaseName in ["RD, RDA"]):
return max(dramconfig.tCCD_L, getReadAccessTime())
elif(SecondPhase in ["WR","WRA"]):
return dramconfig.tRL + getReadAccessTime() - dramconfig.tWL + 2*dramconfig.clk
elif(SecondPhase == "PDNA" ):
return dramconfig.tRL + getReadAccessTime() + dramconfig.clk
elif(FirstPhaseName == "WR"):
if(SecondPhaseName in ["PRE, PRE_ALL", "PDNA"]):
return dramconfig.tWL + dramconfig.getWriteAccessTime() + dramconfig.tWR
elif(SecondPhaseName in ["RD, RDA"]):
return dramconfig.tWL + dramconfig.getWriteAccessTime() + dramconfig.tWTR_L
elif(SecondPhaseName in ["WR, WRA"]):
return max(dramconfig.tCCD_L, burstlength/dramconfig.dataRate)
elif(FirstPhaseName == "RDA"):
if(SecondPhaseName in ["ACT", "PRE_ALL", "AUTO_REFRESH"]):
return dramconfig.tRTP + dramconfig.tRP
elif(SecondPhaseName in ["PDNA","PDNP"]):
return dramconfig.tRL + getReadAccessTime() + dramconfig.clk
elif(FirstPhaseName == "WRA"):
if(SecondPhaseName in ["ACT", "PRE_ALL", "AUTO_REFRESH"]):
return dramconfig.tWL + getWriteAccessTime() + dramconfig.tWR + dramconfig.tRP
elif(SecondPhaseName in ["PDNA","PDNP"]):
return dramconfig.tWL + dramconfig.getWriteAccessTime() + dramconfig.tWR + dramconfig.clk
elif(FirstPhaseName == "AUTO_REFRESH"):
return dramconfig.tRFC
elif(FirstPhaseName in ["PDNA","PDNP"]):
return (FirstPhase[3] - FirstPhase[2]) + dramconfig.tXP - dramconfig.clk
elif(FirstPhaseName == "SREF"):
return (FirstPhase[3] - FirstPhase[2]) + dramconfig.tXSR - dramconfig.clk
return 0
@test
def timing_constraits_on_the_same_bank_hold(connection):
"""Checks that all transitions of two consequtive phases on the same bank meet their timing constraints"""
cursor = connection.cursor()
validTransitions = {}
query = """SELECT PhaseName, phases.ID,PhaseBegin,PhaseEnd 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})
lastRow = cursor.fetchone()
for currentRow in cursor:
constraint = timing_constraint(lastRow,currentRow)
if(currentRow[2] - lastRow[2] + constraint < 0):
return TestFailed("Phase {0}({1}) starts {2} after Start of Phase {3}({4}). Minimal time is {5}".format(
currentRow[1],currentRow[0],formatTime(currentRow[2]-lastRow[2]),lastRow[1],lastRow[0], formatTime(constraint)))
lastRow = currentRow
return TestSuceeded()
@test
def row_buffer_is_used_correctly(connection):
"""Checks that each bank's row buffer is used correctly"""
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"""
#phases that precharge the bank and close the rowbuffer
prechargingPhases = set(['PRE','PRE_ALL','RDA','WRA'])
#phases that require the bank to be in active state and the rowbuffer to be opened
accessingPhases = set(['RD','RDA', 'WR', 'WRA', 'PRE'])
#phases that require the bank to be in precharged state and the robuffer to be closed
idlePhases = set(['ACT', 'PDNP', 'AUTO_REFRESH', 'SREF'])
for bankNumber in range(dramconfig.numberOfBanks):
cursor.execute(query,{"bank": bankNumber})
rowBufferIsClosed = True
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 idlePhases and rowBufferIsClosed == False):
return TestFailed("Phase {0}({1}) needs a closed rowbuffer".format(currentRow[1], currentRow[0]))
if(currentRow[0] == 'ACT'):
rowBufferIsClosed = False
if(currentRow[0] in prechargingPhases):
rowBufferIsClosed = True
return TestSuceeded()
#----------- activate checks ---------------------------------------
@test
def activate_to_activate_holds(connection):
"""Checks that all activates are far enough apart(JESD229 229, P. 27)"""
cursor = connection.cursor()
cursor.execute("SELECT phases.ID,PhaseBegin,TBankGroup FROM Phases INNER JOIN transactions ON phases.transact=transactions.ID WHERE PhaseName = 'ACT' ORDER BY PhaseBegin")
lastRow = cursor.fetchone()
for currentRow in cursor:
timeBetweenActivates = currentRow[1] - lastRow[1]
if (currentRow[2] == lastRow[2]):
minTime = dramconfig.tRRD_L
else:
minTime = dramconfig.tRRD_S
if(timeBetweenActivates < minTime):
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), formatTime(minTime)))
lastRow = currentRow
return TestSuceeded()
@test
def activate_to_activate_on_same_bank_holds(connection):
"""Checks that all activates on the same bank are far enough apart (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 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_holds(connection):
"""Checks that the n-Activate constraint is met everywhere(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.tNAW):
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.tNAW)))
return TestSuceeded()
# ----------- read/write checks ---------------------------------------
@test
def read_to_read_holds(connection):
"""Check that the read operations do not intefere with each other on the data bus"""
cursor = connection.cursor()
cursor.execute("SELECT phases.ID,PhaseBegin,TBankGroup FROM Phases INNER JOIN transactions ON phases.transact=transactions.ID WHERE PhaseName IN ('RD','RDA') ORDER BY PhaseBegin")
lastRow = cursor.fetchone()
for currentRow in cursor:
timeBetweenReads = currentRow[1] - lastRow[1]
if (currentRow[2] == lastRow[2]):
minTime = max(dramconfig.tCCD_L,dramconfig.getReadAccessTime())
else:
minTime = max(dramconfig.tCCD_S,dramconfig.getReadAccessTime())
if(timeBetweenReads < minTime):
return TestFailed("Reads with PhaseIDs {0} and {1} are {2} apart. Minimum time between two reads is {3}".format(currentRow[0], lastRow[0],formatTime(timeBetweenReads), minTime))
lastRow = currentRow
return TestSuceeded()
@test
def write_to_write_holds(connection):
"""Check that the write operations do not intefere with each other on the data bus"""
cursor = connection.cursor()
cursor.execute("SELECT phases.ID,PhaseBegin,TBankGroup FROM Phases INNER JOIN transactions ON phases.transact=transactions.ID WHERE PhaseName IN ('WR','WRA') ORDER BY PhaseBegin")
lastRow = cursor.fetchone()
for currentRow in cursor:
timeBetweenWrites = currentRow[1] - lastRow[1]
if (currentRow[2] == lastRow[2]):
minTime = max(dramconfig.tCCD_L,dramconfig.getWriteAccessTime())
else:
minTime = max(dramconfig.tCCD_S,dramconfig.getWriteAccessTime())
if(timeBetweenWrites < minTime):
return TestFailed("Writes with PhaseIDs {0} and {1} are {2} apart. Minimum time between two writes is {3}".format(currentRow[0], lastRow[0],formatTime(timeBetweenWrites), minTime))
lastRow = currentRow
return TestSuceeded()
@test
def write_to_read_and_read_to_write_hold(connection):
"""Checks that read and write operation do not interfere with each other on the data bus
and that the write-to-read constraint is met"""
cursor = connection.cursor()
query = """SELECT Phases.ID,PhaseBegin,PhaseName,TBankGroup 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"]):
#write to read
if (currentRow[3] == lastRow[3]):
tWTR = dramconfig.tWTR_L
else:
tWTR = dramconfig.tWTR_S
minWriteToRead = dramconfig.tWL + dramconfig.getWriteAccessTime() + tWTR
writeToRead = currentRow[1] - lastRow[1]
if(writeToRead < minWriteToRead ):
return TestFailed("Read {0} starts {1} after start of write {2}. Minimum time is {3}".
format(currentRow[0],formatTime(writeToRead),lastRow[0], formatTime(minWriteToRead)))
elif(currentRow[2] in ["WR","WRA"] and lastRow[2] in ["RD","RDA"]):
#read to write
minReadToWrite = dramconfig.tRL + dramconfig.getReadAccessTime() - dramconfig.tWL + dramconfig.clk * 2
readToWrite = currentRow[1] - lastRow[1]
if(readToWrite < minReadToWrite ):
return TestFailed("Write {0} starts {1} after start of read {2}. Minimum time is {3}".
format(currentRow[0],formatTime(readToWrite),lastRow[0], formatTime(minWriteToRead)))
lastRow = currentRow
return TestSuceeded()
@test
def read_holds_dll_constraint_after_sref(connection):
"""Checks that all read operations are delayed long enough after the end of the self refresh powerdown state"""
cursor = connection.cursor()
query = """SELECT Phases.ID,PhaseBegin,PhaseName,TBankGroup from Phases INNER JOIN Transactions ON Phases.Transact = Transactions.ID AND TBank = :bank
WHERE PhaseName IN ('RD', 'RDA', 'SREF') ORDER BY PhaseBegin"""
for bankNumber in range(dramconfig.numberOfBanks):
cursor.execute(query,{"bank": bankNumber})
lastRow = cursor.fetchone()
for currentRow in cursor:
if(currentRow[2] in ["RD","RDA"] and lastRow[2] == 'SREF'):
srefEndToRead = currentRow[1] - (lastRow[1] - dramconfig.clk)
if(srefEndToRead < dramconfig.tXSRDLL ):
return TestFailed("Read {0} starts {1} after end of sref {2}. Minimum time is {3}".
format(currentRow[0],formatTime(srefEndToRead),lastRow[0], formatTime(dramconfig.tXSRDLL)))
lastRow = currentRow
return TestSuceeded()
# ----------- powerdown checks ---------------------------------------
# @test
# def sref_active_for_minimal_time(connection):
# """Checks that after entering self refresh powerndown state, the state is active for a minimal time (JEDEC 229, P. 41)"""
#
# cursor = connection.cursor()
# cursor.execute("SELECT ID, PhaseEnd-clk-PhaseBegin FROM Phases, GeneralInfo 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 pdna_pdnp_active_for_minimal_time(connection):
# """Checks that after entering active/precharged powerdown, the state is active for a minimal time (JEDEC 229, P. 41)"""
#
# cursor = connection.cursor()
# cursor.execute("SELECT ID,PhaseName, PhaseEnd-PhaseBegin FROM Phases, GeneralInfo WHERE PhaseName IN ('PDNA', 'PDNP') ")
# for currentRow in cursor:
# if(currentRow[2] < dramconfig.tCKE):
# return TestFailed("{0} with ID {1} is {2} long. Minimal time in SREF is {3}".format(currentRow[1], currentRow[0], formatTime(currentRow[2]), dramconfig.tCKE))
# return TestSuceeded()
# -------------------------- interface methods --------------------
def runTests(pathToTrace):
print(pathToTrace)
connection = sqlite3.connect(pathToTrace)
dramconfig.readConfigFromFiles(connection)
testResults = []
numberOfFailedTest = 0
print("================================")
print("RUNNING TEST ON {0}".format(pathToTrace))
print("-----------------------------\n")
for test in tests:
testResult = test(connection)
testName = test.__name__.replace("_"," ")
testResults.append((testName, testResult.passed,testResult.message))
if(testResult.passed):
print("[passed] {0}".format(testName))
else:
print("[failed] {0} failed. Message: {1}".format(testName, testResult.message))
numberOfFailedTest = numberOfFailedTest + 1
print("\n-----------------------------")
if(numberOfFailedTest == 0):
print("All tests passed")
else:
print("{0} of {1} tests passed".format(len(tests) - numberOfFailedTest,len(tests)))
print("================================")
connection.close()
return testResults
if __name__ == "__main__":
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w')
for i in range(1,len(sys.argv)):
runTests(sys.argv[i])