diff --git a/dram/.settings/language.settings.xml b/dram/.settings/language.settings.xml index d60268a9..26f9f756 100644 --- a/dram/.settings/language.settings.xml +++ b/dram/.settings/language.settings.xml @@ -4,7 +4,7 @@ - + @@ -14,7 +14,7 @@ - + diff --git a/dram/resources/configs/amconfigs/am_ddr4.xml b/dram/resources/configs/amconfigs/am_ddr4.xml index 7494e586..73d9cb36 100755 --- a/dram/resources/configs/amconfigs/am_ddr4.xml +++ b/dram/resources/configs/amconfigs/am_ddr4.xml @@ -13,8 +13,8 @@ - - + + + + + + + + + + + + + diff --git a/dram/resources/configs/memspecs/MatzesWideIO-short.xml b/dram/resources/configs/memspecs/MatzesWideIO-short.xml index 7993b990..09e23645 100644 --- a/dram/resources/configs/memspecs/MatzesWideIO-short.xml +++ b/dram/resources/configs/memspecs/MatzesWideIO-short.xml @@ -21,8 +21,8 @@ - + + diff --git a/dram/resources/configs/memspecs/MatzesWideIO.xml b/dram/resources/configs/memspecs/MatzesWideIO.xml index d8fc4025..22996aa3 100644 --- a/dram/resources/configs/memspecs/MatzesWideIO.xml +++ b/dram/resources/configs/memspecs/MatzesWideIO.xml @@ -21,8 +21,8 @@ - + + diff --git a/dram/resources/scripts/tests.py b/dram/resources/scripts/tests.py index c104e3bb..bea32111 100644 --- a/dram/resources/scripts/tests.py +++ b/dram/resources/scripts/tests.py @@ -3,6 +3,7 @@ import sqlite3 import math import os import xml.etree.ElementTree as ET +from sets import Set def getPathToConfigs(): return os.path.dirname(__file__).replace("/scripts","/configs") @@ -10,6 +11,9 @@ def getPathToConfigs(): 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") @@ -32,7 +36,7 @@ def getClock(connection): class DramConfig(object): memoryType = "" - bankwiseLogic = False + bankwiseLogic = 0 clk = 0 unitOfTime = "" dataRate = 0 @@ -68,73 +72,83 @@ class DramConfig(object): print("Parsing dram configuration") memspec = getMemspec(connection) - bankwiseLogic = getValueFromConfigXML(getMemconfig(connection), "bankwiseLogic") - clk = getClock(connection) - self.clk = clk[0] - self.unitOfTime = clk[1].lower() + clkWithUnit = getClock(connection) + self.clk = clkWithUnit[0] + self.unitOfTime = clkWithUnit[1].lower() - self.numberOfBanks = getValueFromConfigXML(memspec, "nbrOfBanks") - self.burstLength = getValueFromConfigXML(memspec, "burstLength") + self.bankwiseLogic = getIntValueFromConfigXML(getMemconfig(connection), "bankwiseLogic") + self.numberOfBanks = getIntValueFromConfigXML(memspec, "nbrOfBanks") + self.burstLength = getIntValueFromConfigXML(memspec, "burstLength") self.memoryType = getValueFromConfigXML(memspec, "memoryType") - self.dataRate = getValueFromConfigXML(memspec, "dataRate") - + self.dataRate = getIntValueFromConfigXML(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.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 * getValueFromConfigXML(memspec, "CCD") + self.tCCD_S = self.clk * getIntValueFromConfigXML(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.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 = 0 - self.tCKESR = self.clk * getValueFromConfigXML(memspec, "CKESR") - self.tCKE = self.clk * getValueFromConfigXML(memspec, "CKE") - self.tXP = self.clk * getValueFromConfigXML(memspec, "XP") + 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 * getValueFromConfigXML(memspec, "XS") + self.tXSR = self.clk * getIntValueFromConfigXML(memspec, "XS") self.tXSRDLL = self.tXSR - self.tAL = self.clk * getValueFromConfigXML(memspec, "AL") - self.tRFC = self.clk * getValueFromConfigXML(memspec, "RFC") + self.tAL = self.clk * getIntValueFromConfigXML(memspec, "AL") + self.tRFC = self.clk * getIntValueFromConfigXML(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"); + 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 some coins and try again") def clkAlign(self, value): return math.ceil(1.0*value/self.clk)*self.clk + def getWriteAcessTime(self): + if(self.dataRate == 1): + return self.clk*(self.burstLength - 1) + elif (self.memoryType == "DDR4"): + return self.clk*self.burstLength/self.dataRate + + def getReadAcessTime(self): + return self.burstLength/self.dataRate * dramconfig.clk + + def __init__(self): pass @@ -172,12 +186,12 @@ def formatTime(time): # ----------- checks --------------------------------------- -@test +#@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": 6}) + cursor.execute(query, {"clk": dramconfig.clk}) result = cursor.fetchone() @@ -186,7 +200,7 @@ def commands_are_clockaligned(connection): result[0], formatTime(result[1]), formatTime(result[2]), formatTime(dramconfig.clk))) return TestSuceeded() -@test +#@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() @@ -207,27 +221,132 @@ def commandbus_slots_are_used_once(connection): return TestSuceeded() -@test -def command_sequences_are_valid(connection): +#@test +def phase_transitions_are_valid(connection): + """Checks if the transition of two consequtive phases is valid""" cursor = connection.cursor() - cursor.execute("SELECT group_concat(phaseName),transact FROM phases GROUP BY transact") + validTransitions = {} - 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' - ]) + 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 - 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() -@test +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, getReadAcessTime()) + elif(SecondPhase in ["WR","WRA"]): + return dramconfig.tRL + getReadAcessTime() - dramconfig.tWL + 2*dramconfig.clk + elif(SecondPhase == "PDNA" ): + return dramconfig.tRL + getReadAcessTime() + dramconfig.clk + + elif(FirstPhaseName == "WR"): + if(SecondPhaseName in ["PRE, PRE_ALL", "PDNA"]): + return dramconfig.tWL + dramconfig.getWriteAcessTime() + dramconfig.tWR + elif(SecondPhaseName in ["RD, RDA"]): + return dramconfig.tWL + dramconfig.getWriteAcessTime() + 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 + getReadAcessTime() + dramconfig.clk + + elif(FirstPhaseName == "WRA"): + if(SecondPhaseName in ["ACT", "PRE_ALL", "AUTO_REFRESH"]): + return dramconfig.tWL + getWriteAcessTime() + dramconfig.tWR + dramconfig.tRP + elif(SecondPhaseName in ["PDNA","PDNP"]): + return dramconfig.tWL + dramconfig.getWriteAcessTime() + 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_same_bank(connection): + """Checks that two consecutive phases on the same bank satisfy timing constraint""" + 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): cursor = connection.cursor() query = """SELECT PhaseName, phases.ID FROM phases INNER JOIN transactions ON phases.transact=transactions.ID WHERE TBank=:bank @@ -237,10 +356,11 @@ def row_buffer_is_used_correctly(connection): cursor.execute(query,{"bank": bankNumber}) rowBufferIsClosed = True + #phases that precharge the bank - prechargingPhases = set(['PRE','PRE_ALL','RDA','WRA']) + closingPhases = set(['PRE','PRE_ALL','RDA','WRA']) #phases that require the bank to be precharged - accessingPhases = set(['RD,RDA,WR,WRA,SREF,AUTO_REFRESH']) + accessingPhases = set(['RD, RDA, WR, WRA, SREF, AUTO_REFRESH']) for currentRow in cursor: @@ -253,106 +373,69 @@ def row_buffer_is_used_correctly(connection): else: return TestFailed("Phase {0}({1}) activates an already activated rowbuffer".format(currentRow[1],currentRow[0])) - if(currentRow[0] in prechargingPhases): + if(currentRow[0] in closingPhases): 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() +#----------- activate checks --------------------------------------- +@test +def activate_to_activate(connection): + """Checks minimal time between two activates (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), minTime)) + lastRow = currentRow + return TestSuceeded() -# @test -# def phases_on_bank_are_sequential(connection): -# cursor = connection.cursor() -# query = """SELECT PhaseBegin,PhaseEnd,phases.ID,PhaseName FROM phases INNER JOIN transactions on transactions.ID = phases.transact WHERE Tbank=:bank AND phaseName not IN ('REQ','RESP')""" - -# for bankNumber in range(dramconfig.numberOfBanks): -# cursor.execute(query,{"bank": bankNumber}) -# lastRow = cursor.fetchone() - -# for currentRow in cursor: -# if(currentRow[0] < lastRow[1] and not ((currentRow[3]=="RD" and lastRow[3]=="RD") -# or (currentRow[3]=="PRE" and lastRow[3]=="RD") or (currentRow[3] == "WR" and lastRow[3] == "WR"))): - -# return TestFailed("Phases with PhaseIDs {0}({1}) and {2}({3}) should not interleave".format( -# currentRow[2], currentRow[3],lastRow[2],lastRow[3])) -# lastRow = currentRow - -# return TestSuceeded() - -# #@test -# def phase_lengths_are_correct(connection): -# query = """SELECT phases.ID,PhaseName, PhaseEnd-PhaseBegin,Burstlength FROM Phases INNER JOIN transactions ON transactions.ID = phases.transact """ -# cursor = connection.cursor() -# cursor.execute(query) +@test +def activate_to_activate_on_same_bank(connection): + """Checks minimal time between two activates on the same bank (JEDEC 229, P. 27)""" + cursor = connection.cursor() + query = "SELECT Phases.ID,PhaseBegin from Phases INNER JOIN Transactions ON Phases.Transact = Transactions.ID WHERE PhaseName = 'ACT' AND TBANK = :bank ORDER BY PhaseBegin" -# for currentRow in cursor: -# 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 --------------------------------------- - -# @test -# def activate_to_activate(connection): -# """Checks minimal time between two activates (JEDEC 229, P. 27)""" -# cursor = connection.cursor() -# cursor.execute("SELECT ID,PhaseBegin from Phases WHERE PhaseName = 'ACT' ORDER BY PhaseBegin") -# lastRow = cursor.fetchone() - -# for currentRow in cursor: -# timeBetweenActivates = currentRow[1] - lastRow[1]; -# if(timeBetweenActivates < dramconfig.tRRD): -# return TestFailed("Activates with PhaseIDs {0} and {1} are {2} apart. Minimum time between two activates is {3}".format(currentRow[0], lastRow[0],formatTime(timeBetweenActivates), dramconfig.tRRD)) -# else: -# lastRow = currentRow -# return TestSuceeded() - - -# @test -# def activate_to_activate_on_same_bank(connection): -# """Checks minimal time between two activates on the same bank (JEDEC 229, P. 27)""" -# cursor = connection.cursor() -# query = "SELECT Phases.ID,PhaseBegin from Phases INNER JOIN Transactions ON Phases.Transact = Transactions.ID WHERE PhaseName = 'ACT' AND TBANK = :bank ORDER BY PhaseBegin" + for 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.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 --------------------------------------- @@ -400,50 +483,30 @@ def row_buffer_is_used_correctly(connection): # return TestSuceeded() -# @test -# def write_or_read_to_precharge(connection): -# """Checks minimal time between write/read and precharge (JEDEC 229, P. 37)""" -# cursor = connection.cursor() -# query = """SELECT Phases.ID,PhaseBegin,PhaseEnd,PhaseName from Phases INNER JOIN Transactions ON Phases.Transact = Transactions.ID -# WHERE PhaseName IN ('RD','WR', 'PRE', 'PRE_ALL') AND TBANK = :bank ORDER BY PhaseBegin""" - -# minReadStartToPrecharge = dramconfig.burstLength * dramconfig.clk -# minWriteEndToPreStart = dramconfig.tWR +@test +def sref_active_for_minimal_time(connection): + """Checks that SREF 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() -# for bankNumber in range(dramconfig.numberOfBanks): - -# cursor.execute(query,{"bank": bankNumber}) -# lastRow = cursor.fetchone() +@test +def pdna_pdnp_active_for_minimal_time(connection): + """Checks that PDNA,PDNP are 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() -# for currentRow in cursor: -# if(currentRow[3] in ["PRE","PRE_ALL"] and lastRow[3] == "RD"): -# readStartToPrecharge = currentRow[1] - lastRow[1] -# if(readStartToPrecharge < minReadStartToPrecharge): -# return TestFailed("Precharge with PhaseID {0} starts {1} after start of RD {2}. Minimum time between end of read and start of precharge is {3}". -# format(currentRow[0],formatTime(readStartToPrecharge),lastRow[0], formatTime(minReadStartToPrecharge))) - -# elif(currentRow[3] in ["PRE","PRE_ALL"] and lastRow[3] == "WR"): -# writeEndToPrecharge = currentRow[1] - lastRow[2] -# if(writeEndToPrecharge < minWriteEndToPreStart): -# return TestFailed("Precharge with PhaseID {0} starts {1} after end of WR {2}. Minimum time between end of write and start of precharge is {3}". -# format(currentRow[0],formatTime(writeEndToPrecharge),lastRow[0], formatTime(minWriteEndToPreStart))) - -# lastRow = currentRow -# return TestSuceeded() - - -# @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): + print(pathToTrace) connection = sqlite3.connect(pathToTrace) dramconfig.readConfigFromFiles(connection) @@ -460,9 +523,9 @@ def runTests(pathToTrace): testResults.append((testName, testResult.passed,testResult.message)) if(testResult.passed): - print("{0} passed".format(testName)) + print("[passed] {0}".format(testName)) else: - print(">>>>>>{0} failed. Message: {1}".format(testName, testResult.message)) + print("[failed] {0} failed. Message: {1}".format(testName, testResult.message)) numberOfFailedTest = numberOfFailedTest + 1 print("\n-----------------------------") @@ -477,6 +540,7 @@ def runTests(pathToTrace): return testResults if __name__ == "__main__": - path = sys.argv[1] - runTests(path) + sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0) + for i in range(1,len(sys.argv)): + runTests(sys.argv[i]) \ No newline at end of file diff --git a/dram/resources/simulations/first.xml b/dram/resources/simulations/first.xml index dc58d0d5..fd972286 100644 --- a/dram/resources/simulations/first.xml +++ b/dram/resources/simulations/first.xml @@ -1,13 +1,13 @@ - MICRON_4Gb_DDR4-1866_8bit_A.xml - am_wideio.xml + JEDEC_256Mb_WIDEIO_SDR-266_128bit.xml + am_wideioFourBanks.xml fr_fcfs.xml fr_fcfs_bankwise.xml - chstone-jpeg_32.stl + mediabench-fractal_32.stl diff --git a/dram/resources/simulations/sim-batch.xml b/dram/resources/simulations/sim-batch.xml index 0df37abc..de8731c6 100644 --- a/dram/resources/simulations/sim-batch.xml +++ b/dram/resources/simulations/sim-batch.xml @@ -1,26 +1,27 @@ - - MatzesWideIO.xml - am_wideio.xml + + JEDEC_256Mb_WIDEIO_SDR-266_128bit.xml + am_wideioFourBanks.xml fr_fcfs.xml fr_fcfs_bankwise.xml - mediabench-adpcmencode_32.stl + mediabench-c-ray-1.1_32.stl - - MatzesWideIO.xml - am_wideio.xml + + + MICRON_4Gb_DDR4-1866_8bit_A.xml + am_ddr4.xml fr_fcfs.xml fr_fcfs_bankwise.xml - mediabench-adpcmencode_32.stl + mediabench-c-ray-1.1_32.stl diff --git a/dram/src/core/TimingCalculation.cpp b/dram/src/core/TimingCalculation.cpp index 36811e91..d81f99a4 100644 --- a/dram/src/core/TimingCalculation.cpp +++ b/dram/src/core/TimingCalculation.cpp @@ -53,31 +53,19 @@ sc_time getExecutionTime(Command command, tlm::tlm_generic_payload& payload) } else if (command == Command::Read) { - return config.tRL + getBurstLengthOnDataStrobe(payload.get_streaming_width()); + return config.tRL + getReadAcessTime(); } else if (command == Command::ReadA) { - return getBurstLengthOnDataStrobe(payload.get_streaming_width()) + max(config.tRP, config.tRL); + return config.tRTP + config.tRP; } - else if (command == Command::Write || command == Command::WriteA) + else if (command == Command::Write) { - sc_time lockTime; - Configuration& config = Configuration::getInstance(); - if(config.DataRate == 1) - lockTime = getBurstLengthOnDataStrobe(payload.get_streaming_width()) - config.Timings.clk; - else //special case DDR4 -> always 4 clocks - { - lockTime = config.Timings.clk * config.BurstLength / config.DataRate; - } - - if (command == Command::Write) - { - return config.Timings.tWL + lockTime; - } - else - { - return config.Timings.tWL + lockTime + config.Timings.tWR; - } + return config.tWL + getWriteAcessTime(); + } + else if (command == Command::WriteA) + { + return config.tWL + getWriteAcessTime() + config.tWR + config.tRP; } else if (command == Command::PrechargeAll) { @@ -117,28 +105,39 @@ sc_time getMinimalExecutionTime(Command command, tlm::tlm_generic_payload& paylo } } - bool isClkAligned(sc_time time, sc_time clk) { -return !((time / clk) - ceil(time / clk)); + return !((time / clk) - ceil(time / clk)); } bool TimeInterval::timeIsInInterval(sc_time time) { -return (start < time && time < end); + return (start < time && time < end); } bool TimeInterval::intersects(TimeInterval other) { -return other.timeIsInInterval(this->start) || this->timeIsInInterval(other.start); + return other.timeIsInInterval(this->start) || this->timeIsInInterval(other.start); } -sc_time getBurstLengthOnDataStrobe(unsigned int burstlength) +sc_time getReadAcessTime() { -Configuration& config = Configuration::getInstance(); -sc_assert((burstlength / config.DataRate) > 0); + Configuration& config = Configuration::getInstance(); + return config.BurstLength/config.DataRate*config.Timings.clk; +} -return config.Timings.clk * (burstlength / config.DataRate); +sc_time getWriteAcessTime() +{ + Configuration& config = Configuration::getInstance(); + + if (config.DataRate == 1) + { + return config.Timings.clk * (config.BurstLength-1) ; + } + else + { + return config.Timings.clk * config.BurstLength / config.DataRate; + } } } diff --git a/dram/src/core/TimingCalculation.h b/dram/src/core/TimingCalculation.h index b579240c..996bc364 100644 --- a/dram/src/core/TimingCalculation.h +++ b/dram/src/core/TimingCalculation.h @@ -31,7 +31,8 @@ struct TimeInterval sc_time getMinimalExecutionTime(Command command, tlm::tlm_generic_payload& payload); sc_time getExecutionTime(Command command, tlm::tlm_generic_payload& payload); -sc_time getBurstLengthOnDataStrobe(unsigned int burstlength); +sc_time getReadAcessTime(); +sc_time getWriteAcessTime(); sc_time getDelayToMeetConstraint(sc_time previous, sc_time start, sc_time constraint); enum Alignment {UP, DOWN}; diff --git a/dram/src/core/configuration/MemSpecLoader.cpp b/dram/src/core/configuration/MemSpecLoader.cpp index 7468aaf8..d281d277 100644 --- a/dram/src/core/configuration/MemSpecLoader.cpp +++ b/dram/src/core/configuration/MemSpecLoader.cpp @@ -138,7 +138,7 @@ void MemSpecLoader::loadWideIO(Configuration& config, XMLElement* memspec) config.Timings.tWR = clk * queryUIntParameter(timings, "WR"); config.Timings.tWTR_S = clk * queryUIntParameter(timings, "WTR"); config.Timings.tWTR_L = config.Timings.tWTR_S; - config.Timings.tRTP = SC_ZERO_TIME; //TODO .. not defined in jedec. bl on datastrobe used + config.Timings.tRTP = clk * queryUIntParameter(timings, "RTP"); config.Timings.tCKESR = clk * queryUIntParameter(timings, "CKESR"); config.Timings.tCKE = clk * queryUIntParameter(timings, "CKE"); config.Timings.tXP = clk * queryUIntParameter(timings, "XP"); diff --git a/dram/src/core/refresh/RefreshManager.cpp b/dram/src/core/refresh/RefreshManager.cpp index 5c8536fc..a9569f09 100644 --- a/dram/src/core/refresh/RefreshManager.cpp +++ b/dram/src/core/refresh/RefreshManager.cpp @@ -27,12 +27,13 @@ RefreshManager::~RefreshManager() bool RefreshManager::hasCollision(const CommandSchedule& schedule) { - return schedule.getEnd() > nextPlannedRefresh; + return schedule.getStart() < controller.state.getLastCommand(Command::AutoRefresh).getEnd() || schedule.getEnd() > nextPlannedRefresh; } bool RefreshManager::hasCollision(const ScheduledCommand& command) { - return command.getEnd() > nextPlannedRefresh; + + return command.getStart() < controller.state.getLastCommand(Command::AutoRefresh).getEnd() || command.getEnd() > nextPlannedRefresh; } void RefreshManager::scheduleRefresh(tlm::tlm_generic_payload& payload, sc_time time) diff --git a/dram/src/core/refresh/RefreshManagerBankwise.cpp b/dram/src/core/refresh/RefreshManagerBankwise.cpp index 2d058f5d..0073510d 100644 --- a/dram/src/core/refresh/RefreshManagerBankwise.cpp +++ b/dram/src/core/refresh/RefreshManagerBankwise.cpp @@ -17,7 +17,7 @@ namespace core { RefreshManagerBankwise::RefreshManagerBankwise(ControllerCore& controller) : controller(controller) { - for(Bank bank : controller.getBanks()) + for (Bank bank : controller.getBanks()) { setUpDummy(refreshPayloads[bank], bank); planNextRefresh(bank); @@ -30,13 +30,14 @@ RefreshManagerBankwise::~RefreshManagerBankwise() bool RefreshManagerBankwise::hasCollision(const CommandSchedule& schedule) { - return schedule.getEnd() > nextPlannedRefreshs[schedule.getBank()]; + return schedule.getStart() < controller.state.getLastCommand(Command::AutoRefresh, schedule.getBank()).getEnd() + || schedule.getEnd() > nextPlannedRefreshs[schedule.getBank()]; } bool RefreshManagerBankwise::hasCollision(const ScheduledCommand& command) { - return command.getEnd() > nextPlannedRefreshs[command.getBank()]; -} + return command.getStart() < controller.state.getLastCommand(Command::AutoRefresh, command.getBank()).getEnd() + || command.getEnd() > nextPlannedRefreshs[command.getBank()];} void RefreshManagerBankwise::scheduleRefresh(tlm::tlm_generic_payload& payload, sc_time time) { @@ -81,7 +82,5 @@ bool RefreshManagerBankwise::isInvalidated(tlm::tlm_generic_payload& payload, sc return nextPlannedRefreshs[DramExtension::getExtension(payload).getBank()] > time; } - - } /* namespace core */ diff --git a/dram/src/core/scheduling/ScheduledCommand.cpp b/dram/src/core/scheduling/ScheduledCommand.cpp index 1a78eca4..99b76f89 100644 --- a/dram/src/core/scheduling/ScheduledCommand.cpp +++ b/dram/src/core/scheduling/ScheduledCommand.cpp @@ -97,23 +97,16 @@ TimeInterval ScheduledCommand::getIntervalOnDataStrobe() const TimingConfiguration& timings = Configuration::getInstance().Timings; - sc_time burstLengthOnDataStrobe = getBurstLengthOnDataStrobe(getBurstLength()); - if (getCommand() == Command::Read || getCommand() == Command::ReadA) { - return TimeInterval(getStart() + timings.tRL, - getStart() + timings.tRL + burstLengthOnDataStrobe); + return TimeInterval(getStart() + timings.tRL,getStart() + timings.tRL + getReadAcessTime()); } else { - return TimeInterval(getStart() + timings.tWL - timings.clk / 2, - getStart() + timings.tWL + burstLengthOnDataStrobe - timings.clk / 2); + return TimeInterval(getStart() + timings.tWL - timings.clk / 2, getStart() + timings.tWL + getWriteAcessTime() - timings.clk / 2); } } -bool ScheduledCommand::collidesOnDataStrobe(const ScheduledCommand& cmd) const -{ - return cmd.getIntervalOnDataStrobe().intersects(getIntervalOnDataStrobe()); -} + } diff --git a/dram/src/core/scheduling/ScheduledCommand.h b/dram/src/core/scheduling/ScheduledCommand.h index 44bb4412..0a561631 100644 --- a/dram/src/core/scheduling/ScheduledCommand.h +++ b/dram/src/core/scheduling/ScheduledCommand.h @@ -51,12 +51,10 @@ public: unsigned int getBurstLength() const; bool operator ==(const ScheduledCommand& b) const; - bool commandIsIn(const std::vector& commandSet) const; TimeInterval getIntervalOnDataStrobe() const; - bool collidesOnDataStrobe(const ScheduledCommand& command) const; private: Command command; diff --git a/dram/src/core/scheduling/checker/ActivateChecker.cpp b/dram/src/core/scheduling/checker/ActivateChecker.cpp index f949bf2e..b1729862 100644 --- a/dram/src/core/scheduling/checker/ActivateChecker.cpp +++ b/dram/src/core/scheduling/checker/ActivateChecker.cpp @@ -23,13 +23,24 @@ void ActivateChecker::delayToSatisfyConstraints(ScheduledCommand& command) const ScheduledCommand lastCommandOnBank = state.getLastScheduledCommand(command.getBank()); if (lastCommandOnBank.isValidCommand()) { - if (isIn(lastCommandOnBank.getCommand(), { Command::Precharge, Command::AutoRefresh, - Command::ReadA, Command::WriteA })) + if (lastCommandOnBank.getCommand() == Command::Precharge) { - command.delayToMeetConstraint(lastCommandOnBank.getEnd(), SC_ZERO_TIME); + command.delayToMeetConstraint(lastCommandOnBank.getStart(), config.Timings.tRP); } - else if (lastCommandOnBank.getCommand() == Command::PDNPX - || lastCommandOnBank.getCommand() == Command::PDNAX) + else if (lastCommandOnBank.getCommand() == Command::ReadA) + { + command.delayToMeetConstraint(lastCommandOnBank.getStart(), config.Timings.tRTP + config.Timings.tRP); + } + else if (lastCommandOnBank.getCommand() == Command::WriteA) + { + command.delayToMeetConstraint(lastCommandOnBank.getStart(), + config.Timings.tWL + getWriteAcessTime() + config.Timings.tWR + config.Timings.tRP); + } + else if (lastCommandOnBank.getCommand() == Command::AutoRefresh) + { + command.delayToMeetConstraint(lastCommandOnBank.getStart(), config.Timings.tRFC); + } + else if (lastCommandOnBank.getCommand() == Command::PDNPX || lastCommandOnBank.getCommand() == Command::PDNAX) { command.delayToMeetConstraint(lastCommandOnBank.getStart(), config.Timings.tXP); } @@ -38,14 +49,12 @@ void ActivateChecker::delayToSatisfyConstraints(ScheduledCommand& command) const command.delayToMeetConstraint(lastCommandOnBank.getStart(), config.Timings.tXSR); } else - reportFatal("Activate Checker", - "Activate can not follow " + commandToString(lastCommandOnBank.getCommand())); + reportFatal("Activate Checker", "Activate can not follow " + commandToString(lastCommandOnBank.getCommand())); } delay_to_satisfy_activateToActivate_sameBank(command); - while (!(state.bus.isFree(command.getStart()) - && satsfies_activateToActivate_differentBank(command) + while (!(state.bus.isFree(command.getStart()) && satsfies_activateToActivate_differentBank(command) && satisfies_nActivateWindow(command))) { command.delayStart(config.Timings.clk); @@ -55,8 +64,7 @@ void ActivateChecker::delayToSatisfyConstraints(ScheduledCommand& command) const void ActivateChecker::delay_to_satisfy_activateToActivate_sameBank(ScheduledCommand& command) const { - ScheduledCommand lastActivateOnBank = state.getLastCommand(Command::Activate, - command.getBank()); + ScheduledCommand lastActivateOnBank = state.getLastCommand(Command::Activate, command.getBank()); if (lastActivateOnBank.isValidCommand()) { command.delayToMeetConstraint(lastActivateOnBank.getStart(), config.Timings.tRC); @@ -68,9 +76,7 @@ bool ActivateChecker::satsfies_activateToActivate_differentBank(ScheduledCommand for (auto act : state.lastActivates) { sc_time time = act.first; - sc_time tRRD = - (command.getBankGroup() == act.second.getBankGroup()) ? - config.Timings.tRRD_L : config.Timings.tRRD_S; + sc_time tRRD = (command.getBankGroup() == act.second.getBankGroup()) ? config.Timings.tRRD_L : config.Timings.tRRD_S; if ((time < command.getStart() && command.getStart() - time < tRRD) || (command.getStart() <= time && time - command.getStart() < tRRD)) diff --git a/dram/src/core/scheduling/checker/PowerDownChecker.cpp b/dram/src/core/scheduling/checker/PowerDownChecker.cpp index 0acec216..c1a19d75 100644 --- a/dram/src/core/scheduling/checker/PowerDownChecker.cpp +++ b/dram/src/core/scheduling/checker/PowerDownChecker.cpp @@ -6,6 +6,7 @@ */ #include "PowerDownChecker.h" +#include "../../../common/Utils.h" namespace core { void PowerDownChecker::delayToSatisfyConstraints(ScheduledCommand& command) const @@ -18,12 +19,38 @@ void PowerDownChecker::delayToSatisfyConstraints(ScheduledCommand& command) cons { ScheduledCommand lastCommandOnBank = state.getLastScheduledCommand(command.getBank()); - if (lastCommandOnBank.isValidCommand() - && lastCommandOnBank.commandIsIn( { Command::Read, Command::ReadA, Command::WriteA })) + if (lastCommandOnBank.isValidCommand()) { - command.delayToMeetConstraint(lastCommandOnBank.getEnd(), config.Timings.clk); + if (lastCommandOnBank.getCommand() == Command::Read || lastCommandOnBank.getCommand() == Command::ReadA) + { + command.delayToMeetConstraint(lastCommandOnBank.getStart(), + config.Timings.tRL + getReadAcessTime() + config.Timings.clk); + } + else if (lastCommandOnBank.getCommand() == Command::Write) + { + command.delayToMeetConstraint(lastCommandOnBank.getStart(), + config.Timings.tWL + getWriteAcessTime() + config.Timings.tWR); + } + else if (lastCommandOnBank.getCommand() == Command::WriteA) + { + command.delayToMeetConstraint(lastCommandOnBank.getStart(), + config.Timings.tWL + getWriteAcessTime() + config.Timings.tWR + config.Timings.clk); + } + else if (lastCommandOnBank.getCommand() == Command::AutoRefresh) + { + command.delayToMeetConstraint(lastCommandOnBank.getStart(), config.Timings.tRFC); + } + else if (lastCommandOnBank.getCommand() == Command::PDNPX || lastCommandOnBank.getCommand() == Command::PDNAX) + { + command.delayToMeetConstraint(lastCommandOnBank.getStart(), config.Timings.tXP); + } + else + { + reportFatal("Powerdown checker", commandToString(command.getCommand()) + " can not follow " + commandToString(lastCommandOnBank.getCommand())); + } } } + else if (command.getCommand() == Command::PDNAX) { command.delayToMeetConstraint(state.getLastCommand(Command::PDNA).getStart(), config.Timings.tCKE); diff --git a/dram/src/core/scheduling/checker/PrechargeAllChecker.cpp b/dram/src/core/scheduling/checker/PrechargeAllChecker.cpp index 2a0d93d4..67033a71 100644 --- a/dram/src/core/scheduling/checker/PrechargeAllChecker.cpp +++ b/dram/src/core/scheduling/checker/PrechargeAllChecker.cpp @@ -21,30 +21,32 @@ void PrechargeAllChecker::delayToSatisfyConstraints(ScheduledCommand& command) c { if (lastCommand.getCommand() == Command::Read) { - command.delayToMeetConstraint(lastCommand.getStart(), lastCommand.getBurstLength() * config.Timings.clk); + command.delayToMeetConstraint(lastCommand.getStart(), config.Timings.tRTP); + } + else if (lastCommand.getCommand() == Command::ReadA) + { + command.delayToMeetConstraint(lastCommand.getStart(), config.Timings.tRTP + config.Timings.tRP); } else if (lastCommand.getCommand() == Command::Write) { - command.delayToMeetConstraint(lastCommand.getEnd(), config.Timings.tWR); + command.delayToMeetConstraint(lastCommand.getStart(), config.Timings.tWL + getWriteAcessTime() + config.Timings.tWR); } - else if (lastCommand.getCommand() == Command::WriteA) + else if(lastCommand.getCommand() == Command::WriteA) { - command.delayToMeetConstraint(lastCommand.getEnd(), SC_ZERO_TIME); - if (config.Timings.tWR > config.Timings.tRP) - command.delayToMeetConstraint(lastCommand.getEnd(), config.Timings.tWR - config.Timings.tRP); + command.delayToMeetConstraint(lastCommand.getStart(), config.Timings.tWL + getWriteAcessTime() + config.Timings.tWR + config.Timings.tRP); } - else if (lastCommand.commandIsIn( { Command::PDNAX, Command::PDNPX })) + else if (lastCommand.getCommand() == Command::AutoRefresh) { - command.delayToMeetConstraint(lastCommand.getEnd(), config.Timings.tXP); + command.delayToMeetConstraint(lastCommand.getStart(), config.Timings.tRFC); + } + else if (lastCommand.getCommand() == Command::PDNAX || lastCommand.getCommand() == Command::PDNPX) + { + command.delayToMeetConstraint(lastCommand.getStart(), config.Timings.tXP); } else if (lastCommand.getCommand() == Command::SREFX) { command.delayToMeetConstraint(lastCommand.getEnd(), config.Timings.tXSR); } - else if (lastCommand.commandIsIn( { Command::ReadA, Command::AutoRefresh })) - { - command.delayToMeetConstraint(lastCommand.getEnd(), SC_ZERO_TIME); - } else reportFatal("Precharge All Checker", "Precharge All can not follow " + commandToString(lastCommand.getCommand())); diff --git a/dram/src/core/scheduling/checker/PrechargeChecker.cpp b/dram/src/core/scheduling/checker/PrechargeChecker.cpp index b3bff928..c33df3b1 100644 --- a/dram/src/core/scheduling/checker/PrechargeChecker.cpp +++ b/dram/src/core/scheduling/checker/PrechargeChecker.cpp @@ -20,16 +20,15 @@ void PrechargeChecker::delayToSatisfyConstraints(ScheduledCommand& command) cons { if (lastCommand.getCommand() == Command::Read) { - command.delayToMeetConstraint(lastCommand.getStart(), - max(config.Timings.tRTP, lastCommand.getIntervalOnDataStrobe().getLength())); + command.delayToMeetConstraint(lastCommand.getStart(),config.Timings.tRTP); } else if (lastCommand.getCommand() == Command::Write) { - command.delayToMeetConstraint(lastCommand.getEnd(), config.Timings.tWR); + command.delayToMeetConstraint(lastCommand.getStart(), config.Timings.tWL + getWriteAcessTime() + config.Timings.tWR); } else if (lastCommand.getCommand() == Command::PDNAX) { - command.delayToMeetConstraint(lastCommand.getEnd(), config.Timings.tXP); + command.delayToMeetConstraint(lastCommand.getStart(), config.Timings.tXP); } else reportFatal("Precharge Checker", "Precharge can not follow " + commandToString(lastCommand.getCommand())); diff --git a/dram/src/core/scheduling/checker/ReadChecker.cpp b/dram/src/core/scheduling/checker/ReadChecker.cpp index 52d5879b..a153ff31 100644 --- a/dram/src/core/scheduling/checker/ReadChecker.cpp +++ b/dram/src/core/scheduling/checker/ReadChecker.cpp @@ -8,6 +8,7 @@ #include "ReadChecker.h" #include "../../TimingCalculation.h" #include "../../../common/Utils.h" +#include "WriteChecker.h" namespace core { @@ -23,19 +24,22 @@ void ReadChecker::delayToSatisfyConstraints(ScheduledCommand& command) const { if (lastCommand.getCommand() == Command::Activate) { - command.delayToMeetConstraint(lastCommand.getEnd(), SC_ZERO_TIME); + command.delayToMeetConstraint(lastCommand.getStart(), config.Timings.tRCD); } - else if (lastCommand.getCommand() == Command::Read - || lastCommand.getCommand() == Command::Write) + else if (lastCommand.getCommand() == Command::Read) { + command.delayToMeetConstraint(lastCommand.getStart(), ReadChecker::readToRead(lastCommand,command)); } - else if (lastCommand.getCommand() == Command::PDNAX || lastCommand.getCommand() == Command::PDNPX) + else if (lastCommand.getCommand() == Command::Write) { - command.delayToMeetConstraint(lastCommand.getStart(), config.Timings.tXP);//TODO DLL ?? + command.delayToMeetConstraint(lastCommand.getStart(), ReadChecker::writeToRead(lastCommand, command)); + } + else if (lastCommand.getCommand() == Command::PDNPX || lastCommand.getCommand() == Command::PDNAX) + { + command.delayToMeetConstraint(lastCommand.getStart(), config.Timings.tXP); } else - reportFatal("Read Checker", - "Read can not follow " + commandToString(lastCommand.getCommand())); + reportFatal("Read Checker", "Read can not follow " + commandToString(lastCommand.getCommand())); } while (!state.bus.isFree(command.getStart()) || collidesOnDataStrobe(command)) @@ -44,7 +48,6 @@ void ReadChecker::delayToSatisfyConstraints(ScheduledCommand& command) const } } - bool ReadChecker::collidesOnDataStrobe(ScheduledCommand& read) const { for (ScheduledCommand& strobeCommand : state.lastDataStrobeCommands) @@ -56,46 +59,23 @@ bool ReadChecker::collidesOnDataStrobe(ScheduledCommand& read) const return false; } -bool ReadChecker::collidesWithStrobeCommand(ScheduledCommand& read, - ScheduledCommand& strobeCommand) const +bool ReadChecker::collidesWithStrobeCommand(ScheduledCommand& read, ScheduledCommand& strobeCommand) const { - //read to read if (strobeCommand.getCommand() == Command::Read || strobeCommand.getCommand() == Command::ReadA) { - bool collision = read.collidesOnDataStrobe(strobeCommand); - - sc_time tCCD = - (read.getBankGroup() == strobeCommand.getBankGroup()) ? - config.Timings.tCCD_L : config.Timings.tCCD_S; - bool casToCas = - (getDistance(read.getStart(), strobeCommand.getStart()) < tCCD) ? true : false; - - return collision || casToCas; + return getDistance(read.getStart(),strobeCommand.getStart()) < ReadChecker::readToRead(strobeCommand,read); } - else if (strobeCommand.getCommand() == Command::Write - || strobeCommand.getCommand() == Command::WriteA) + else if (strobeCommand.getCommand() == Command::Write || strobeCommand.getCommand() == Command::WriteA) { - //read to write if (strobeCommand.getStart() >= read.getStart()) - { - return strobeCommand.getStart() < read.getIntervalOnDataStrobe().end; - } - //write to read + return getDistance(read.getStart(), strobeCommand.getStart()) < WriteChecker::readToWrite(read,strobeCommand); else - { - sc_time tWTR = - (read.getBankGroup() == strobeCommand.getBankGroup()) ? - config.Timings.tWTR_L : config.Timings.tWTR_S; - - return read.getStart() - < clkAlign(strobeCommand.getIntervalOnDataStrobe().end, Alignment::DOWN) + tWTR; - } + return getDistance(strobeCommand.getStart(), read.getStart()) < ReadChecker::writeToRead(strobeCommand, read); } else { reportFatal("Read Checker", - "Invalid strobeCommand in data strobe commands " - + commandToString(strobeCommand.getCommand())); + "Invalid strobeCommand in data strobe commands " + commandToString(strobeCommand.getCommand())); return true; } } @@ -103,9 +83,29 @@ bool ReadChecker::collidesWithStrobeCommand(ScheduledCommand& read, void ReadChecker::delayToSatisfyDLL(ScheduledCommand& read) const { ScheduledCommand lastSREFX = state.getLastCommand(Command::SREFX, read.getBank()); - if(lastSREFX.isValidCommand()) + if (lastSREFX.isValidCommand()) read.delayToMeetConstraint(lastSREFX.getStart(), config.Timings.tXSRDLL); } +sc_time ReadChecker::readToRead(ScheduledCommand& firstRead, ScheduledCommand& secondRead) +{ + sc_assert(firstRead.getCommand() == Command::Read || firstRead.getCommand() == Command::ReadA); + sc_assert(secondRead.getCommand() == Command::Read || secondRead.getCommand() == Command::ReadA); + + TimingConfiguration& config = Configuration::getInstance().Timings; + sc_time tCCD = (firstRead.getBankGroup() == secondRead.getBankGroup()) ? config.tCCD_L : config.tCCD_S; + return max(tCCD, getReadAcessTime()); +} + +sc_time ReadChecker::writeToRead(ScheduledCommand& write, ScheduledCommand& read) +{ + sc_assert(read.getCommand() == Command::Read || read.getCommand() == Command::ReadA); + sc_assert(write.getCommand() == Command::Write || write.getCommand() == Command::WriteA); + + TimingConfiguration& config = Configuration::getInstance().Timings; + sc_time tWTR = (write.getBankGroup() == read.getBankGroup()) ? config.tWTR_L : config.tWTR_S; + return config.tWL + getWriteAcessTime() + tWTR; +} + } /* namespace controller */ diff --git a/dram/src/core/scheduling/checker/ReadChecker.h b/dram/src/core/scheduling/checker/ReadChecker.h index 78508a79..3f1fae9d 100644 --- a/dram/src/core/scheduling/checker/ReadChecker.h +++ b/dram/src/core/scheduling/checker/ReadChecker.h @@ -22,6 +22,9 @@ public: virtual void delayToSatisfyConstraints(ScheduledCommand& command) const override; + static sc_time readToRead(ScheduledCommand& firstRead, ScheduledCommand& secondRead); + static sc_time writeToRead(ScheduledCommand& write, ScheduledCommand& read); + private: const Configuration& config; ControllerState& state; diff --git a/dram/src/core/scheduling/checker/RefreshChecker.cpp b/dram/src/core/scheduling/checker/RefreshChecker.cpp index 0066173c..6f4f2c5c 100644 --- a/dram/src/core/scheduling/checker/RefreshChecker.cpp +++ b/dram/src/core/scheduling/checker/RefreshChecker.cpp @@ -18,23 +18,32 @@ void RefreshChecker::delayToSatisfyConstraints(ScheduledCommand& command) const if (lastCommandOnBank.isValidCommand()) { - if (lastCommandOnBank.getCommand() == Command::Precharge || lastCommandOnBank.getCommand() == Command::PrechargeAll ) + if (lastCommandOnBank.getCommand() == Command::Precharge || lastCommandOnBank.getCommand() == Command::PrechargeAll) { - command.delayToMeetConstraint(lastCommandOnBank.getEnd(), SC_ZERO_TIME); + command.delayToMeetConstraint(lastCommandOnBank.getStart(), config.Timings.tRP); } - else if (lastCommandOnBank.getCommand() == Command::PDNPX) + else if (lastCommandOnBank.getCommand() == Command::ReadA) { - command.delayToMeetConstraint(lastCommandOnBank.getEnd(), config.Timings.tXP); + command.delayToMeetConstraint(lastCommandOnBank.getStart(), config.Timings.tRTP + config.Timings.tRP); } - else if (lastCommandOnBank.getCommand() == Command::SREFX) + else if (lastCommandOnBank.getCommand() == Command::WriteA) { - command.delayToMeetConstraint(lastCommandOnBank.getEnd(), config.Timings.tXSR); + command.delayToMeetConstraint(lastCommandOnBank.getStart(), + config.Timings.tWL + getWriteAcessTime() + config.Timings.tWR + config.Timings.tRP); } - else if (lastCommandOnBank.getCommand() == Command::AutoRefresh) + else if (lastCommandOnBank.getCommand() == Command::PDNPX || lastCommandOnBank.getCommand() == Command::PDNAX) { + command.delayToMeetConstraint(lastCommandOnBank.getStart(), config.Timings.tXP); } - else - reportFatal("Refresh Checker", "Refresh can not follow " + commandToString(lastCommandOnBank.getCommand())); +// else if (lastCommandOnBank.getCommand() == Command::SREFX) +// { +// command.delayToMeetConstraint(lastCommandOnBank.getEnd(), config.Timings.tXSR); +// } +// else if (lastCommandOnBank.getCommand() == Command::AutoRefresh) +// { +// } +// else +// reportFatal("Refresh Checker", "Refresh can not follow " + commandToString(lastCommandOnBank.getCommand())); } state.bus.moveCommandToNextFreeSlot(command); diff --git a/dram/src/core/scheduling/checker/WriteChecker.cpp b/dram/src/core/scheduling/checker/WriteChecker.cpp index 36b946c1..e7c45541 100644 --- a/dram/src/core/scheduling/checker/WriteChecker.cpp +++ b/dram/src/core/scheduling/checker/WriteChecker.cpp @@ -8,6 +8,7 @@ #include "WriteChecker.h" #include "../../TimingCalculation.h" #include "../../../common/Utils.h" +#include "ReadChecker.h" namespace core { @@ -21,13 +22,17 @@ void WriteChecker::delayToSatisfyConstraints(ScheduledCommand& command) const { if (lastCommand.getCommand() == Command::Activate) { - command.delayToMeetConstraint(lastCommand.getEnd(), SC_ZERO_TIME); + command.delayToMeetConstraint(lastCommand.getStart(), config.Timings.tRCD); } - else if (lastCommand.getCommand() == Command::Read || lastCommand.getCommand() == Command::Write) + else if (lastCommand.getCommand() == Command::Read) { - + command.delayToMeetConstraint(lastCommand.getStart(), WriteChecker::readToWrite(lastCommand, command)); } - else if (lastCommand.getCommand() == Command::PDNAX) + else if (lastCommand.getCommand() == Command::Write) + { + command.delayToMeetConstraint(lastCommand.getStart(), WriteChecker::writeToWrite(lastCommand, command)); + } + else if (lastCommand.getCommand() == Command::PDNPX || lastCommand.getCommand() == Command::PDNAX) { command.delayToMeetConstraint(lastCommand.getStart(), config.Timings.tXP); } @@ -54,34 +59,16 @@ bool WriteChecker::collidesOnDataStrobe(ScheduledCommand& write) const bool WriteChecker::collidesWithStrobeCommand(ScheduledCommand& write, ScheduledCommand& strobeCommand) const { - //write to write if (strobeCommand.getCommand() == Command::Write || strobeCommand.getCommand() == Command::WriteA) { - bool collision = write.collidesOnDataStrobe(strobeCommand); - - sc_time tCCD = - (write.getBank().getBankGroup() == strobeCommand.getBank().getBankGroup()) ? - config.Timings.tCCD_L : config.Timings.tCCD_S; - bool casToCas = (getDistance(write.getStart(), strobeCommand.getStart()) < tCCD) ? true : false; - - return collision || casToCas; + return getDistance(write.getStart(),strobeCommand.getStart()) < WriteChecker::writeToWrite(strobeCommand,write); } else if (strobeCommand.getCommand() == Command::Read || strobeCommand.getCommand() == Command::ReadA) { - //write to read if (strobeCommand.getStart() >= write.getStart()) - { - sc_time tWTR = - (write.getBank().getBankGroup() == strobeCommand.getBank().getBankGroup()) ? - config.Timings.tWTR_L : config.Timings.tWTR_S; - - return strobeCommand.getStart() < clkAlign(write.getIntervalOnDataStrobe().end, Alignment::DOWN) + tWTR; - } - //read to write + return getDistance(write.getStart(),strobeCommand.getStart()) < ReadChecker::writeToRead(write, strobeCommand); else - { - return write.getStart() < strobeCommand.getIntervalOnDataStrobe().end; - } + return getDistance(strobeCommand.getStart(), write.getStart()) < WriteChecker::readToWrite(strobeCommand, write); } else { @@ -91,4 +78,23 @@ bool WriteChecker::collidesWithStrobeCommand(ScheduledCommand& write, ScheduledC } } +sc_time WriteChecker::writeToWrite(ScheduledCommand& firstWrite, ScheduledCommand& secondWrite) +{ + sc_assert(firstWrite.getCommand() == Command::Write || firstWrite.getCommand() == Command::WriteA); + sc_assert(secondWrite.getCommand() == Command::Write || secondWrite.getCommand() == Command::WriteA); + + TimingConfiguration& config = Configuration::getInstance().Timings; + sc_time tCCD = (firstWrite.getBankGroup() == secondWrite.getBankGroup()) ? config.tCCD_L : config.tCCD_S; + return max(tCCD, getWriteAcessTime()); +} + +sc_time WriteChecker::readToWrite(ScheduledCommand& read, ScheduledCommand& write) +{ + sc_assert(read.getCommand() == Command::Read || read.getCommand() == Command::ReadA); + sc_assert(write.getCommand() == Command::Write || write.getCommand() == Command::WriteA); + + TimingConfiguration& config = Configuration::getInstance().Timings; + return config.tRL + getReadAcessTime() - config.tWL + config.clk * 2; +} + } /* namespace controller */ diff --git a/dram/src/core/scheduling/checker/WriteChecker.h b/dram/src/core/scheduling/checker/WriteChecker.h index 48cc2ed9..64dd726e 100644 --- a/dram/src/core/scheduling/checker/WriteChecker.h +++ b/dram/src/core/scheduling/checker/WriteChecker.h @@ -21,11 +21,16 @@ public: virtual ~WriteChecker() {} virtual void delayToSatisfyConstraints(ScheduledCommand& command) const override; + + static sc_time writeToWrite(ScheduledCommand& firstWrite, ScheduledCommand& secondWrite); + static sc_time readToWrite(ScheduledCommand& read, ScheduledCommand& write); private: bool collidesOnDataStrobe(ScheduledCommand& write) const; bool collidesWithStrobeCommand(ScheduledCommand& write, ScheduledCommand& strobeCommand) const; const Configuration& config; ControllerState& state; + + }; } /* namespace controller */ diff --git a/dram/src/simulation/Simulation.cpp b/dram/src/simulation/Simulation.cpp index daa64c39..384d03c0 100644 --- a/dram/src/simulation/Simulation.cpp +++ b/dram/src/simulation/Simulation.cpp @@ -129,6 +129,7 @@ void Simulation::stop() { wait(terminateSimulation); report("\nTerminating simulation"); + wait(sc_time(50, SC_NS)); controller->terminateSimulation(); wait(sc_time(50, SC_NS)); TlmRecorder::getInstance().closeConnection(); diff --git a/dram/src/simulation/TracePlayer.h b/dram/src/simulation/TracePlayer.h index daaeaa13..38423f04 100644 --- a/dram/src/simulation/TracePlayer.h +++ b/dram/src/simulation/TracePlayer.h @@ -39,9 +39,7 @@ public: if (!file.is_open()) SC_REPORT_FATAL(0, (string("Could not open trace ") + pathToTrace).c_str()); - if(burstLength == 0) - this->burstlenght = core::Configuration::getInstance().BurstLength; - + this->burstlenght = core::Configuration::getInstance().BurstLength; iSocket.register_nb_transport_bw(this, &TracePlayer::nb_transport_bw); }