From e354fb5652a1008035b78e4b056cbe2b734ac246 Mon Sep 17 00:00:00 2001 From: robert Date: Sun, 13 Apr 2014 11:01:21 +0200 Subject: [PATCH] added recording of memconfig, memspec. Tests use the memconfig in a trace for the timing --- dram/resources/scripts/tests.py | 573 ++++++++++-------- dram/resources/simulations/first.xml | 14 - .../core/configuration/TimingConfiguration.h | 2 +- dram/src/simulation/Simulation.cpp | 5 +- 4 files changed, 339 insertions(+), 255 deletions(-) delete mode 100644 dram/resources/simulations/first.xml diff --git a/dram/resources/scripts/tests.py b/dram/resources/scripts/tests.py index 8d827256..781a4ed8 100644 --- a/dram/resources/scripts/tests.py +++ b/dram/resources/scripts/tests.py @@ -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 diff --git a/dram/resources/simulations/first.xml b/dram/resources/simulations/first.xml deleted file mode 100644 index 91776355..00000000 --- a/dram/resources/simulations/first.xml +++ /dev/null @@ -1,14 +0,0 @@ - - MICRON_4Gb_DDR4-1866_8bit_A.xml - - memconfig.xml - - - - - chstone-mips_32.stl - empty.stl - - - diff --git a/dram/src/core/configuration/TimingConfiguration.h b/dram/src/core/configuration/TimingConfiguration.h index 7bac0d9a..79602d5d 100644 --- a/dram/src/core/configuration/TimingConfiguration.h +++ b/dram/src/core/configuration/TimingConfiguration.h @@ -31,7 +31,7 @@ struct TimingConfiguration sc_time tRP; //precharge-time (pre -> act same bank) sc_time tRAS; //active-time (act -> pre same bank) sc_time tRC; //RAS-cycle-time (min time bw 2 succesive ACT to same bank) - sc_time tCCD_S; //TODO: relevant? max(bl, tCCD) + sc_time tCCD_S; //max(bl, tCCD) is relevant for rd->rd sc_time tCCD_L; sc_time tRTP; //Read to precharge sc_time tRRD_S; //min time bw 2 succesive ACT to different banks (different bank group) diff --git a/dram/src/simulation/Simulation.cpp b/dram/src/simulation/Simulation.cpp index f2f6f7ab..2d85b4ab 100644 --- a/dram/src/simulation/Simulation.cpp +++ b/dram/src/simulation/Simulation.cpp @@ -30,15 +30,16 @@ Simulation::Simulation(string name, string pathToResources, string traceName, Dr TlmRecorder::sqlScriptURI = pathToResources + string("scripts/createTraceDB.sql"); Configuration::memconfigUri = pathToResources + string("configs/memconfigs/") + setup.memconfig; Configuration::memspecUri = pathToResources + string("configs/memspecs/") + setup.memspec; + TlmRecorder::getInstance().recordMemconfig(setup.memconfig); + TlmRecorder::getInstance().recordMemspec(setup.memspec); - //setup dram dram = new Dram<>("dram"); arbiter = new Arbiter("arbiter"); controller = new Controller<>("controller"); player1 = new TracePlayer<>("player1", pathToResources + string("traces/") + devices[0].trace, devices[0].burstLength, this); player2 = new TracePlayer<>("player2", pathToResources + string("traces/") + devices[1].trace, devices[1].burstLength, this); - + TlmRecorder::getInstance().recordTracenames(devices[0].trace + "," + devices[1].trace); player1->iSocket.bind(arbiter->tSockets[0]); player2->iSocket.bind(arbiter->tSockets[1]);