From 4d3de95225460c440c34ece5b861a8f79886a9d7 Mon Sep 17 00:00:00 2001 From: robert Date: Wed, 2 Apr 2014 23:13:02 +0200 Subject: [PATCH] new metrics --- dram/resources/configs/addressConfig.xml | 8 +- dram/resources/scripts/metrics.py | 97 ++++- dram/resources/scripts/stlGenerator.py | 19 +- dram/resources/scripts/tests.py | 397 +++++++++++------- dram/src/common/DebugManager.cpp | 19 + dram/src/common/DebugManager.h | 2 + dram/src/core/Controller.cpp | 2 + dram/src/core/Controller.h | 2 - dram/src/core/ControllerState.cpp | 10 +- dram/src/core/ControllerState.h | 6 +- dram/src/core/TimingConfiguration.h | 12 +- dram/src/core/refresh/RefreshManager.cpp | 1 + .../core/refresh/RefreshManagerBankwise.cpp | 3 +- .../scheduling/checker/ActivateChecker.cpp | 52 ++- .../core/scheduling/checker/ActivateChecker.h | 6 +- .../scheduling/checker/PrechargeChecker.cpp | 2 +- .../scheduling/checker/PrechargeChecker.h | 2 +- dram/src/simulation/GroupPlayer.h | 160 +++++++ dram/src/simulation/arbiter.h | 8 +- dram/src/simulation/main.cpp | 26 +- dram/src/simulation/traceplayer.h | 74 ++-- 21 files changed, 652 insertions(+), 256 deletions(-) create mode 100644 dram/src/simulation/GroupPlayer.h diff --git a/dram/resources/configs/addressConfig.xml b/dram/resources/configs/addressConfig.xml index 1dc6c4eb..7494e586 100755 --- a/dram/resources/configs/addressConfig.xml +++ b/dram/resources/configs/addressConfig.xml @@ -16,6 +16,12 @@ - + + + diff --git a/dram/resources/scripts/metrics.py b/dram/resources/scripts/metrics.py index c5303e55..c6c18641 100644 --- a/dram/resources/scripts/metrics.py +++ b/dram/resources/scripts/metrics.py @@ -1,17 +1,48 @@ import sys import sqlite3 - metrics = [] +threadMetrics = [] def metric(function): metrics.append(function) return function -@metric -def average_response_latency(connection): +def threadMetric(function): + threadMetrics.append(function) + return function + +def getThreads(connection): cursor = connection.cursor() - cursor.execute("SELECT avg(end-begin) FROM ranges") + cursor.execute("SELECT DISTINCT(TThread) FROM transactions WHERE TThread != 0 ORDER BY TThread") + result = [] + for currentRow in cursor: + result.append(currentRow[0]) + return result + +def getNumberOfBanks(connection): + cursor = connection.cursor() + cursor.execute("SELECT NumberOfBanks FROM generalInfo") + result = cursor.fetchone() + return result[0] + + +@metric +def average_response_latency_in_ns(connection): + cursor = connection.cursor() + cursor.execute("""SELECT avg(ranges.end-ranges.begin) FROM transactions INNER JOIN ranges + ON transactions.range = ranges.ID where TThread != 0""") + + result = cursor.fetchone() + return round(result[0],1) + +@threadMetric +def average_response_latency_in_ns(connection, thread): + cursor = connection.cursor() + query = """SELECT avg(ranges.end-ranges.begin) FROM transactions INNER JOIN ranges + ON transactions.range = ranges.ID where TThread = :Thread """ + + cursor.execute(query, {"Thread": thread}) result = cursor.fetchone() return round(result[0],1) @@ -22,6 +53,55 @@ def number_of_activates(connection): result = cursor.fetchone() return result[0] +@metric +def number_of_precharges(connection): + cursor = connection.cursor() + cursor.execute("SELECT COUNT(*) FROM Phases WHERE PhaseName IN ('PRE','PRE_ALL','RDA','WRA')") + result = cursor.fetchone() + return result[0] + +def passRatio(connection): + + numberOfPassWins = {} + numberOfPassLosses = {} + + for thread in getThreads(connection): + numberOfPassWins[thread] = 0 + numberOfPassLosses[thread] = 0 + + for bankNumber in range(getNumberOfBanks(connection)): + cursor = connection.cursor() + query = """SELECT begin,end,transactions.ID,TThread, + TBank from transactions inner join ranges on transactions.range = ranges.id WHERE TBank = :Bank AND TThread != 0""" + cursor.execute(query, {"Bank":bankNumber}) + + for passedRequest in cursor: + passedBegin = passedRequest[0] + passedEnd = passedRequest[1] + passedId = passedRequest[2] + passedThread = passedRequest[3] + + cursor2 = connection.cursor() + query2 = """SELECT begin,end,transactions.ID,TThread, + TBank from transactions inner join ranges on transactions.range = ranges.id + WHERE TBank = :Bank AND :Begin> self.__dramConfigReader.startBits[element] & self.onesMask(self.__dramConfigReader.endBits[element] - self.__dramConfigReader.startBits[element] + 1) + return (address >> self.__dramConfigReader.startBits[element]) & self.onesMask(self.__dramConfigReader.endBits[element] - self.__dramConfigReader.startBits[element] + 1) def formatStlLine(self, line): try: found = re.search('0x[0-9,a-f]+', line).group(0) address = int(found, 16) - decodedAddress = '[Channel: {0} Bank: {1} Row:{2} Column: {3}]'.format(self.parseAttributeFromAddress(address, 'channel'), - self.parseAttributeFromAddress(address, 'bank'), self.parseAttributeFromAddress(address, 'row'), self.parseAttributeFromAddress(address, 'colum')) + decodedAddress = '[Channel: {0} Bank: {0} Row:{1} Col:{2}]'.format(self.parseAttributeFromAddress(address, 'channel'), + self.parseAttributeFromAddress(address, 'bank'), self.parseAttributeFromAddress(address, 'row'), self.parseAttributeFromAddress(address, 'colum')) return line.replace("\n", " ") + decodedAddress except AttributeError: return '' @@ -54,9 +55,11 @@ class StlReader: def printStlPretty(self, filename): f = open(filename) for line in f.readlines(): - print(self.formatStlLine(line)) - - + #print(self.formatStlLine(line)) + found = re.search('0x[0-9,a-f]+', line).group(0) + address = int(found, 16) + print(format(address, '032b') + " " + self.formatStlLine(line)) + class StlGenerator: __actions = [] __time = 0 diff --git a/dram/resources/scripts/tests.py b/dram/resources/scripts/tests.py index 426a853a..46faa6be 100644 --- a/dram/resources/scripts/tests.py +++ b/dram/resources/scripts/tests.py @@ -9,10 +9,11 @@ class DramConfig(object): nActivateWindow = 0 burstLengtht = 2 clk = numberOfBanks = 0 - tRP = tRAS = tRC = tRRD = tRCD = tTAW = tRL = tWL = tWTR = 0 + tRP = tRAS = tRC = tRRD = tRCD = tTAW = tRL = tWL = tWTR = tRFC = tWR = 0 + tReadLength = tWriteLength = 0 def clkAlign(self, value): - return math.ceil(value/self.clk)*self.clk + return math.ceil(1.0*value/self.clk)*self.clk def parseFromXml(self): self.clk = 6 @@ -28,7 +29,12 @@ class DramConfig(object): self.tRL = 3*self.clk self.tWL = 1*self.clk self.tWTR = 3*self.clk + self.tWR = 2*self.clk self.tTAW = self.clkAlign(50) + self.tRFC = self.clkAlign(130) + + self.tReadLength = self.tRL + self.burstLength * self.clk + self.tWriteLength = self.tWL + (self.burstLength - 1) *self.clk def __init__(self): self.parseFromXml() @@ -67,180 +73,257 @@ def commands_are_clockaligned(connection): """Checks that all commands on the command bus are aligned to the system clock""" passedTest = True cursor = connection.cursor() - cursor.execute("SELECT ID, PhaseBegin, PhaseEnd from Phases WHERE PhaseName NOT IN ('REQ','RESP') ORDER BY PhaseBegin") - lastRow = cursor.fetchone() + query = "select ID,PhaseBegin,PhaseEnd from phases where phaseName NOT IN ('REQ','RESP') AND (phaseBegin%:clk!=0 OR phaseEnd%:clk!=0)" + cursor.execute(query, {"clk": 6}) - for currentRow in cursor: - phaseBegin = currentRow[1] - phaseEnd = currentRow[2] - if(phaseBegin % dramconfig.clk != 0): - return TestFailed("Command with PhaseID {0} starts at {1} and is not aligned to system clock ({2})".format( - currentRow[0], formatTime(phaseBegin), formatTime(dramconfig.clk))) - if(phaseEnd % dramconfig.clk != 0): - return TestFailed("Command with PhaseID {0} end at {1} and is not aligned to system clock ({2})".format( - currentRow[0], formatTime(phaseEnd), formatTime(dramconfig.clk))) + result = cursor.fetchone() + + if(result != None): + return TestFailed("Command with PhaseID {0} starts at {1} and ends at, which is not aligned to system clock ({2})".format( + result[0], formatTime(result[1]), formatTime(result[2]), formatTime(dramconfig.clk))) + return TestSuceeded() @test def commandbus_slots_are_used_once(connection): """Checks that no two phases on the command bus start at the same time""" cursor = connection.cursor() - cursor.execute("SELECT ID,PhaseBegin from Phases WHERE PhaseName NOT IN ('REQ', 'RESP') ORDER BY PhaseBegin") - lastRow = cursor.fetchone() + cursor.execute("SELECT PhaseBegin,count FROM (SELECT phaseBegin,count(phasebegin) AS count FROM Phases WHERE PhaseName NOT IN ('RESP','REQ') GROUP BY phaseBegin) WHERE count>1") + result = cursor.fetchone() + + if(result != None): + return TestFailed("Slot on commandbus at time {0} is used twice".format(formatTime(result[0]))) - for currentRow in cursor: - if(lastRow[1] != currentRow[1]): - lastRow = currentRow - else: - return TestFailed("Commandbus slot is used twice by commands with PhaseID {0} and {1}".format(lastRow[0], currentRow[0])) return TestSuceeded() -# ----------- precharge checks --------------------------------------- +@test +def command_sequences_are_valid(connection): + cursor = connection.cursor() + cursor.execute("SELECT group_concat(phaseName),transact FROM phases GROUP BY transact") -# ----------- activate checks --------------------------------------- + validSequences = set(['AUTO_REFRESH','PDNA','PDNP','SREF', + 'PRE,AUTO_REFRESH', 'PRE_ALL,AUTO_REFRESH', + 'REQ,RD,RESP', 'REQ,WR,RESP', 'REQ,RDA,RESP', 'REQ,WRA,RESP', + 'REQ,ACT,RD,RESP', 'REQ,ACT,WR,RESP', 'REQ,ACT,RDA,RESP', 'REQ,ACT,WRA,RESP', + 'REQ,PRE,ACT,RD,RESP', 'REQ,PRE,ACT,WR,RESP', 'REQ,PRE,ACT,RDA,RESP', 'REQ,PRE,ACT,WRA,RESP' + ]) -# @test -# def precharge_before_activate(connection): -# """Checks that all activate commands are preceeded by a precharge or a refresh or a powerdown""" -# cursor = connection.cursor() -# query = """SELECT Phases.ID, PhaseName, PhaseBegin FROM Transactions INNER JOIN Phases ON Phases.Transact = Transactions.ID -# WHERE (TBank = :bank AND PhaseName IN ('ACT','PRE','REFB')) OR PhaseName IN ('REFA','SREF','PDNP','PDNA') ORDER BY PhaseBegin""" - -# for bankNumber in range(dramconfig.numberOfBanks): -# cursor.execute(query,{"bank": bankNumber}) -# lastRow = cursor.fetchone() - -# for currentRow in cursor: -# if(lastRow[1] != currentRow[1] or currentRow[1] != 'ACT'): -# lastRow = currentRow -# else: -# return TestFailed("No precharge between activates with PhaseID {0} and {1}".format(lastRow[0], currentRow[0])) -# return TestSuceeded() - -# @test -# def activate_to_activate(connection): -# """Checks minimal time between two activates (JEDEC 229, P. 27)""" -# cursor = connection.cursor() -# cursor.execute("SELECT ID,PhaseBegin from Phases WHERE PhaseName = 'ACT' ORDER BY PhaseBegin") -# lastRow = cursor.fetchone() - -# for currentRow in cursor: -# timeBetweenActivates = currentRow[1] - lastRow[1]; -# if(timeBetweenActivates < dramconfig.tRRD): -# return TestFailed("Activates with PhaseIDs {0} and {1} are {2} apart. Minimum time between two activates is {3}".format(currentRow[0], lastRow[0],formatTime(timeBetweenActivates), dramconfig.tRRD)) -# else: -# lastRow = currentRow -# return TestSuceeded() - - -# @test -# def activate_to_activate_on_same_bank(connection): -# """Checks minimal time between two activates on the same bank (JEDEC 229, P. 27)""" -# cursor = connection.cursor() -# query = "SELECT Phases.ID,PhaseBegin from Phases INNER JOIN Transactions ON Phases.Transact = Transactions.ID WHERE PhaseName = 'ACT' AND TBANK = :bank ORDER BY PhaseBegin" + for currentRow in cursor: + commandSequence = currentRow[0] + if(commandSequence not in validSequences): + return TestFailed("Transaction {0} generated invalid command sequence {1}".format(currentRow[1], commandSequence)) -# for bankNumber in range(dramconfig.numberOfBanks): -# cursor.execute(query,{"bank": bankNumber}) -# lastRow = cursor.fetchone() + return TestSuceeded() + + +@test +def row_buffer_is_used_correctly(connection): + cursor = connection.cursor() + query = """SELECT PhaseName, phases.ID FROM phases INNER JOIN transactions ON phases.transact=transactions.ID WHERE TBank=:bank + AND PhaseName NOT IN ('REQ','RESP') ORDER BY PhaseBegin""" + + for bankNumber in range(dramconfig.numberOfBanks): + cursor.execute(query,{"bank": bankNumber}) + + rowBufferIsClosed = True + prechargingPhases = set(['PRE','PRE_ALL','RDA','WRA']) + accessingPhases = set(['RD,RDA,WR,WRA,SREF,AUTO_REFRESH']) + + for currentRow in cursor: + + if(currentRow[0] in accessingPhases and rowBufferIsClosed == True): + return TestFailed("Phase {0}({1}) acesses a closed rowbuffer".format(currentRow[1], currentRow[0])) + + if(currentRow[0] == 'ACT'): + if(rowBufferIsClosed == True): + rowBufferIsClosed = False + else: + return TestFailed("Phase {0}({1}) activates an already activated rowbuffer".format(currentRow[1],currentRow[0])) + + if(currentRow[0] in prechargingPhases): + if(rowBufferIsClosed == True and currentRow[0] != 'PRE_ALL'): + return TestFailed("Phase {0}({1}) closes an already closed rowbuffer".format(currentRow[1],currentRow[0])) + else: + rowBufferIsClosed = True + + return TestSuceeded() + + +@test +def phases_on_bank_are_sequential(connection): + cursor = connection.cursor() + query = """SELECT PhaseBegin,PhaseEnd,phases.ID,PhaseName FROM phases INNER JOIN transactions on transactions.ID = phases.transact WHERE Tbank=:bank AND phaseName not IN ('REQ','RESP')""" + + for bankNumber in range(dramconfig.numberOfBanks): + cursor.execute(query,{"bank": bankNumber}) + lastRow = cursor.fetchone() + + for currentRow in cursor: + if(currentRow[0] < lastRow[1] and not ((currentRow[3]=="RD" and lastRow[3]=="RD") + or (currentRow[3]=="PRE" and lastRow[3]=="RD") or (currentRow[3] == "WR" and lastRow[3] == "WR"))): + + return TestFailed("Phases with PhaseIDs {0}({1}) and {2}({3}) should not interleave".format( + currentRow[2], currentRow[3],lastRow[2],lastRow[3])) + lastRow = currentRow + + return TestSuceeded() + +@test +def phase_lengths_are_correct(connection): + query = """SELECT ID,PhaseEnd-PhaseBegin FROM Phases WHERE PhaseName = :command and (PhaseEnd-PhaseBegin)!= :length""" + commandLengths = [('RD', dramconfig.tReadLength), + ('RDA', dramconfig.tReadLength + dramconfig.tRP), + ('WR', dramconfig.tWriteLength), + ('WRA', dramconfig.tWriteLength + dramconfig.tRP), + ('PRE', dramconfig.tRP), + ('ACT', dramconfig.tRCD), + ('AUTO_REFRESH', dramconfig.tRFC)] + + for commandLength in commandLengths: + command = commandLength[0] + length = commandLength[1] + cursor = connection.cursor() + cursor.execute(query, {"command":command, "length" : length}) + result = cursor.fetchone() + if(result != None): + return TestFailed("Phase with ID {0}({1}) has invalid length {2}".format(result[0],command,formatTime(result[1]))) + + return TestSuceeded() + + + + +#----------- activate checks --------------------------------------- + +@test +def activate_to_activate(connection): + """Checks minimal time between two activates (JEDEC 229, P. 27)""" + cursor = connection.cursor() + cursor.execute("SELECT ID,PhaseBegin from Phases WHERE PhaseName = 'ACT' ORDER BY PhaseBegin") + lastRow = cursor.fetchone() + + for currentRow in cursor: + timeBetweenActivates = currentRow[1] - lastRow[1]; + if(timeBetweenActivates < dramconfig.tRRD): + return TestFailed("Activates with PhaseIDs {0} and {1} are {2} apart. Minimum time between two activates is {3}".format(currentRow[0], lastRow[0],formatTime(timeBetweenActivates), dramconfig.tRRD)) + else: + lastRow = currentRow + return TestSuceeded() + + +@test +def activate_to_activate_on_same_bank(connection): + """Checks minimal time between two activates on the same bank (JEDEC 229, P. 27)""" + cursor = connection.cursor() + query = "SELECT Phases.ID,PhaseBegin from Phases INNER JOIN Transactions ON Phases.Transact = Transactions.ID WHERE PhaseName = 'ACT' AND TBANK = :bank ORDER BY PhaseBegin" -# for currentRow in cursor: -# timeBetweenActivates = currentRow[1] - lastRow[1]; -# if(timeBetweenActivates < dramconfig.tRC): -# return TestFailed("Activates with PhaseIDs {0} and {1} are {2} apart. Minimum time between two activates is {3}, since they are on the same bank({4})". -# format(currentRow[0], lastRow[0],formatTime(timeBetweenActivates), dramconfig.tRC)) -# else: -# lastRow = currentRow - -# return TestSuceeded() - -# @test -# def n_activate_window(connection): -# """Checks n-Activate constraint (JEDEC 229, P. 27)""" -# cursor = connection.cursor() -# cursor.execute("SELECT ID,PhaseBegin from Phases WHERE PhaseName = 'ACT' ORDER BY PhaseBegin") -# activateWindow = [] - -# for currentRow in cursor: -# activateWindow.append(currentRow[1]) -# if(len(activateWindow) > dramconfig.nActivateWindow + 1): -# activateWindow.pop(0) -# if(activateWindow[dramconfig.nActivateWindow] - activateWindow[0] < dramconfig.tTAW): -# return TestFailed("Activate with PhaseID {0} and the {1} preceeding activates violate the '{1} activate window' constraint." -# " No more than {1} activates should be in rolling time window of {2}".format(currentRow[0], dramconfig.nActivateWindow,formatTime(dramconfig.tTAW))) -# return TestSuceeded() - - -# # ----------- read checks --------------------------------------- - -# @test -# def activate_to_read(connection): -# """Checks minimal time bewteen activate and following read (JEDEC 229, P. 29)""" -# cursor = connection.cursor() -# query = "SELECT Phases.ID,PhaseBegin,PhaseName from Phases INNER JOIN Transactions ON Phases.Transact = Transactions.ID WHERE PhaseName IN ('ACT','RD') AND TBANK = :bank ORDER BY PhaseBegin" + for bankNumber in range(dramconfig.numberOfBanks): + cursor.execute(query,{"bank": bankNumber}) + lastRow = cursor.fetchone() -# for bankNumber in range(dramconfig.numberOfBanks): + for currentRow in cursor: + timeBetweenActivates = currentRow[1] - lastRow[1]; + if(timeBetweenActivates < dramconfig.tRC): + return TestFailed("Activates with PhaseIDs {0} and {1} are {2} apart. Minimum time between two activates is {3}, since they are on the same bank({4})". + format(currentRow[0], lastRow[0],formatTime(timeBetweenActivates), dramconfig.tRC)) + else: + lastRow = currentRow + + return TestSuceeded() + +@test +def n_activate_window(connection): + """Checks n-Activate constraint (JEDEC 229, P. 27)""" + cursor = connection.cursor() + cursor.execute("SELECT ID,PhaseBegin from Phases WHERE PhaseName = 'ACT' ORDER BY PhaseBegin") + activateWindow = [] + + for currentRow in cursor: + activateWindow.append(currentRow[1]) + if(len(activateWindow) > dramconfig.nActivateWindow + 1): + activateWindow.pop(0) + if(activateWindow[dramconfig.nActivateWindow] - activateWindow[0] < dramconfig.tTAW): + return TestFailed("Activate with PhaseID {0} and the {1} preceeding activates violate the '{1} activate window' constraint." + " No more than {1} activates should be in rolling time window of {2}".format(currentRow[0], dramconfig.nActivateWindow,formatTime(dramconfig.tTAW))) + return TestSuceeded() + + +# ----------- read/write checks --------------------------------------- + +@test +def read_to_read(connection): + """Checks minimal time between two reads(JEDEC 229, P. 29)""" + cursor = connection.cursor() + cursor.execute("SELECT Phases.ID, PhaseBegin, PhaseName from Phases WHERE PhaseName IN ('RD','RDA') ORDER BY PhaseBegin") + lastRow = cursor.fetchone() + + for currentRow in cursor: + if(currentRow[1] < lastRow[1] + dramconfig.tReadLength): + timeBetweenReads = currentRow[1] - lastRow[1]; + clocksBetweenReads = round(timeBetweenReads/dramconfig.clk) + if(clocksBetweenReads % 2 == 1): + return TestFailed("{0} with PhaseID {1} interrupts data acess of {2} {3}. They are {4} clocks ({5}) apart. Numbers of clock between interrupting reads must be even.". + format(currentRow[2], currentRow[0], lastRow[2], lastRow[0], clocksBetweenReads, formatTime(timeBetweenReads))) + lastRow = currentRow + + return TestSuceeded() + +@test +def write_to_read_and_read_to_write(connection): + """Checks minimal time between write and read/read and write (JEDEC 229, P. 33/34)""" + cursor = connection.cursor() + query = """SELECT Phases.ID,PhaseBegin,PhaseName from Phases INNER JOIN Transactions ON Phases.Transact = Transactions.ID + WHERE PhaseName IN ('RD','WR','RDA','WRA') ORDER BY PhaseBegin""" + + cursor.execute(query) + lastRow = cursor.fetchone() + + for currentRow in cursor: + if(currentRow[2] in ["RD","RDA"] and lastRow[2] in ["WR","WRA"]): + writeEndToReadBegin = currentRow[1] - (lastRow[1] + dramconfig.tWriteLength); + if(writeEndToReadBegin < dramconfig.tWTR ): + return TestFailed("Read with PhaseID {0} starts {1} after end of data access of write {2}. Minimum time between end of write and start of read is {3}". + format(currentRow[0],formatTime(writeEndToReadBegin),lastRow[0], formatTime(dramconfig.tWTR ))) + elif(currentRow[2] in ["WR","WRA"] and lastRow[2] in ["RD","RDA"]): + if(currentRow[1] < (lastRow[1]+dramconfig.tReadLength)): + return TestFailed("WR with PhaseID {0} starts before end of data acess of read {1}". + format(currentRow[0], lastRow[0])) + lastRow = currentRow + + return TestSuceeded() + + +@test +def write_or_read_to_precharge(connection): + """Checks minimal time between write/read and precharge (JEDEC 229, P. 37)""" + cursor = connection.cursor() + query = """SELECT Phases.ID,PhaseBegin,PhaseEnd,PhaseName from Phases INNER JOIN Transactions ON Phases.Transact = Transactions.ID + WHERE PhaseName IN ('RD','WR', 'PRE', 'PRE_ALL') AND TBANK = :bank ORDER BY PhaseBegin""" + + minReadStartToPrecharge = dramconfig.burstLength * dramconfig.clk + minWriteEndToPreStart = dramconfig.tWR + + for bankNumber in range(dramconfig.numberOfBanks): -# cursor.execute(query,{"bank": bankNumber}) -# lastRow = cursor.fetchone() - -# for currentRow in cursor: -# if(currentRow[2] == "RD" and lastRow[2] == "ACT"): -# actToReadTime = currentRow[1] - lastRow[1]; -# if(actToReadTime < dramconfig.tRCD): -# return TestFailed("Read with PhaseID {0} starts {1} after activate {2}. Minimum activate to read time is {3}". -# format(currentRow[0],formatTime(actToReadTime),lastRow[0], formatTime(dramconfig.tRCD))) -# lastRow = currentRow - -# return TestSuceeded() - -# @test -# def read_to_read(connection): -# """Checks minimal time between two reads(JEDEC 229, P. 29)""" -# cursor = connection.cursor() -# cursor.execute("SELECT Phases.ID, PhaseBegin, PhaseEnd from Phases WHERE PhaseName = 'RD' ORDER BY PhaseBegin") -# lastRow = cursor.fetchone() - -# for currentRow in cursor: -# if(currentRow[1] < lastRow[2]): -# timeBetweenReads = currentRow[1] - lastRow[1]; -# clocksBetweenReads = round(timeBetweenReads/dramconfig.clk) -# if(clocksBetweenReads % 2 == 1): -# return TestFailed("Read with PhaseID {0} interrupts read {1}. They are {2} clocks ({3}) apart. Numbers of clock between interrupting reads must be even.". -# format(currentRow[0], lastRow[0], clocksBetweenReads, formatTime(timeBetweenReads))) -# lastRow = currentRow - -# return TestSuceeded() - -# @test -# def write_to_read(connection): -# """Checks minimal time between write and following read (JEDEC 229, P. 34)""" -# cursor = connection.cursor() -# query = "SELECT Phases.ID,PhaseBegin,PhaseEnd,PhaseName from Phases INNER JOIN Transactions ON Phases.Transact = Transactions.ID WHERE PhaseName IN ('RD','WR') AND TBANK = :bank ORDER BY PhaseBegin" - -# for bankNumber in range(dramconfig.numberOfBanks): - -# cursor.execute(query,{"bank": bankNumber}) -# lastRow = cursor.fetchone() - -# for currentRow in cursor: -# if(currentRow[3] == "RD" and lastRow[3] == "WR"): -# writeEndToReadBegin = currentRow[1] - lastRow[2]; -# if(writeEndToReadBegin < dramconfig.tWTR ): -# return TestFailed("Read with PhaseID {0} starts {1} after end of write {2}. Minimum time between end of write and start of read is {3}". -# format(currentRow[0],formatTime(writeEndToReadBegin),lastRow[0], formatTime(dramconfig.tWTR ))) -# lastRow = currentRow - -# return TestSuceeded() - - - - - - - + cursor.execute(query,{"bank": bankNumber}) + lastRow = cursor.fetchone() + for currentRow in cursor: + if(currentRow[3] in ["PRE","PRE_ALL"] and lastRow[3] == "RD"): + readStartToPrecharge = currentRow[1] - lastRow[1] + if(readStartToPrecharge < minReadStartToPrecharge): + return TestFailed("Precharge with PhaseID {0} starts {1} after start of RD {2}. Minimum time between end of read and start of precharge is {3}". + format(currentRow[0],formatTime(readStartToPrecharge),lastRow[0], formatTime(minReadStartToPrecharge))) + + elif(currentRow[3] in ["PRE","PRE_ALL"] and lastRow[3] == "WR"): + writeEndToPrecharge = currentRow[1] - lastRow[2] + if(writeEndToPrecharge < minWriteEndToPreStart): + return TestFailed("Precharge with PhaseID {0} starts {1} after end of WR {2}. Minimum time between end of write and start of precharge is {3}". + format(currentRow[0],formatTime(writeEndToPrecharge),lastRow[0], formatTime(minWriteEndToPreStart))) + lastRow = currentRow + return TestSuceeded() # -------------------------- interface methods -------------------- diff --git a/dram/src/common/DebugManager.cpp b/dram/src/common/DebugManager.cpp index 8a96c59c..b397232f 100644 --- a/dram/src/common/DebugManager.cpp +++ b/dram/src/common/DebugManager.cpp @@ -32,6 +32,24 @@ void DebugManager::printDebugMessage(string message, Sender sender, Importance i } } +void DebugManager::printDebugMessage(std::string message, Sender sender, unsigned int senderNumber, + Importance importance) +{ + bool show = count(whiteList.begin(), whiteList.end(), + pair(sender, importance)); + + if (show) + { + cout << importanceToString(importance); + if (printTime) + std::cout << " at " << sc_time_stamp(); + if (printLocation) + std::cout << " in " << senderToString(sender) << "number " << senderNumber; + cout << ": " << message << endl; + } +} + + void DebugManager::addToWhiteList(Sender sender, Importance importance) { whiteList.push_back(pair(sender, importance)); @@ -43,6 +61,7 @@ void DebugManager::addToWhiteList(Sender sender) addToWhiteList(sender, Importance::Warning); } + string DebugManager::importanceToString(Importance importancy) { switch (importancy) diff --git a/dram/src/common/DebugManager.h b/dram/src/common/DebugManager.h index 7d708128..d0553c27 100644 --- a/dram/src/common/DebugManager.h +++ b/dram/src/common/DebugManager.h @@ -25,6 +25,8 @@ public: bool printLocation; void printDebugMessage(std::string message, Sender sender, Importance importance=Importance::Info); + void printDebugMessage(std::string message, Sender sender,unsigned int senderNumber, Importance importance=Importance::Info); + void addToWhiteList(Sender sender, Importance importance); void addToWhiteList(Sender sender); diff --git a/dram/src/core/Controller.cpp b/dram/src/core/Controller.cpp index 7107c97b..d4ad0f10 100644 --- a/dram/src/core/Controller.cpp +++ b/dram/src/core/Controller.cpp @@ -104,6 +104,8 @@ bool Controller::isBusy(sc_time currentTime, Bank bank) void Controller::send(const CommandSchedule& schedule, tlm::tlm_generic_payload& payload) const { + + for (const ScheduledCommand& cmd : schedule.getScheduledCommands()) { wrapper.send(cmd, payload); diff --git a/dram/src/core/Controller.h b/dram/src/core/Controller.h index 8d40a324..2d437df0 100644 --- a/dram/src/core/Controller.h +++ b/dram/src/core/Controller.h @@ -31,8 +31,6 @@ public: bool isBusy(sc_time currentTime, Bank bank); void scheduleRefresh(tlm::tlm_generic_payload& payload, sc_time time); - - const ICommandChecker& getChecker(Command command) const; const BankStates& getBankStates(){return state.bankStates;} void saveState(); diff --git a/dram/src/core/ControllerState.cpp b/dram/src/core/ControllerState.cpp index e9e96522..1786b419 100644 --- a/dram/src/core/ControllerState.cpp +++ b/dram/src/core/ControllerState.cpp @@ -66,10 +66,9 @@ void ControllerState::change(const ScheduledCommand& scheduledCommand) break; case Command::Activate: bankStates.openRowInRowBuffer(scheduledCommand.getBank(), scheduledCommand.getRow()); - nActivateWindow.put(scheduledCommand.getStart()); - activates.blockSlots(scheduledCommand.getStart() - config->Timings.tRRD, - scheduledCommand.getStart() + config->Timings.tRRD, true); + lastActivates.emplace(scheduledCommand.getStart()); break; + case Command::Precharge: bankStates.closeRowBuffer(scheduledCommand.getBank()); break; @@ -85,9 +84,8 @@ void ControllerState::change(const ScheduledCommand& scheduledCommand) void ControllerState::cleanUp(sc_time time) { bus.cleanUpSlots(time); - activates.cleanUpSlots(time); - - lastDataStrobeCommands.remove_if([&](ScheduledCommand command){return command.getEnd() < time;}); + lastDataStrobeCommands.remove_if([&](ScheduledCommand command){return command.getEnd() < time - config->Timings.tStrobeHistory;}); + lastActivates.erase(lastActivates.begin(), lastActivates.lower_bound(time - config->Timings.tActHistory)); } } /* namespace controller */ diff --git a/dram/src/core/ControllerState.h b/dram/src/core/ControllerState.h index fc4a40df..556bbaec 100644 --- a/dram/src/core/ControllerState.h +++ b/dram/src/core/ControllerState.h @@ -24,8 +24,7 @@ class ControllerState { public: ControllerState(Configuration* config) : - bankStates(config->numberOfBanks), nActivateWindow(config->nActivate), bus( - config->Timings.clk), activates(config->Timings.clk), config(config) + bankStates(config->numberOfBanks), bus(config->Timings.clk), config(config) { } virtual ~ControllerState() @@ -42,11 +41,10 @@ public: BankStates bankStates; //used by the various checkers - RingBuffer nActivateWindow; std::map > lastCommandsOnBus; Slots bus; - Slots activates; std::list lastDataStrobeCommands; + std::set lastActivates; private: Configuration* config; diff --git a/dram/src/core/TimingConfiguration.h b/dram/src/core/TimingConfiguration.h index 2488aa6f..440e42b5 100644 --- a/dram/src/core/TimingConfiguration.h +++ b/dram/src/core/TimingConfiguration.h @@ -29,7 +29,7 @@ struct TimingConfiguration for (unsigned int i = 0; i < numberOfBanks; ++i) { - sc_time tRFC = 21*clk; + sc_time tRFC = clkAlign(sc_time(130,SC_NS),clk); //sc_time tREFI = 100*clk; sc_time tREFI = sc_time(15.6, SC_US); //TODO align //tREFI = sc_time(301268, SC_NS); @@ -47,9 +47,11 @@ struct TimingConfiguration tRL = 3*clk; //read latency (read command start to data strobe) tWL = 1*clk; //write latency tTAW = clkAlign(sc_time(50,SC_NS), clk); //two activate window - tRR = 2*clk; //min read to read on same rank - tWW = 1*clk; //min write to write on same rank tWTR = 3*clk;//write to read + tWR = 2*clk; //write recovery (write to precharge) + + tActHistory = tTAW; + tStrobeHistory = tWTR; } sc_time clk; @@ -61,10 +63,10 @@ struct TimingConfiguration sc_time tTAW; sc_time tRL; sc_time tWL; + sc_time tWR; sc_time tWTR; - sc_time tRR; - sc_time tWW; + sc_time tActHistory, tStrobeHistory; std::vector refreshTimings; diff --git a/dram/src/core/refresh/RefreshManager.cpp b/dram/src/core/refresh/RefreshManager.cpp index 57bc5814..98e486d5 100644 --- a/dram/src/core/refresh/RefreshManager.cpp +++ b/dram/src/core/refresh/RefreshManager.cpp @@ -40,6 +40,7 @@ void RefreshManager::scheduleRefresh(tlm::tlm_generic_payload& payload, sc_time ScheduledCommand precharge(Command::PrechargeAll, time, controller.config.Timings.tRP, DramExtension::getExtension(refreshPayloads.at(0))); + controller.commandChecker.at(Command::PrechargeAll)->delayToSatisfyConstraints(precharge); nextRefresh.setStart(precharge.getEnd()); controller.state.change(precharge); diff --git a/dram/src/core/refresh/RefreshManagerBankwise.cpp b/dram/src/core/refresh/RefreshManagerBankwise.cpp index a70660d6..9a6f4a61 100644 --- a/dram/src/core/refresh/RefreshManagerBankwise.cpp +++ b/dram/src/core/refresh/RefreshManagerBankwise.cpp @@ -79,8 +79,7 @@ void RefreshManagerBankwise::RefreshManagerForBank::scheduleRefresh(sc_time time if (controller.state.bankStates.rowBufferIsOpen(bank)) { ScheduledCommand precharge(Command::Precharge, time, controller.config.Timings.tRP, DramExtension::getExtension(refreshPayload)); - - controller.state.bus.moveCommandToNextFreeSlot(precharge); + controller.commandChecker.at(Command::Precharge)->delayToSatisfyConstraints(precharge); nextRefresh.setStart(precharge.getEnd()); controller.state.change(precharge); diff --git a/dram/src/core/scheduling/checker/ActivateChecker.cpp b/dram/src/core/scheduling/checker/ActivateChecker.cpp index 991a090d..8a792b8c 100644 --- a/dram/src/core/scheduling/checker/ActivateChecker.cpp +++ b/dram/src/core/scheduling/checker/ActivateChecker.cpp @@ -5,8 +5,8 @@ * Author: jonny */ -#include #include +#include #include "../../utils/Utils.h" #include "ActivateChecker.h" #include "../../../common/DebugManager.h" @@ -35,11 +35,13 @@ void ActivateChecker::delayToSatisfyConstraints(ScheduledCommand& command) const "Activate can not follow " + commandToString(lastCommandOnBank.getCommand())); } - satisfy_activateToActivate_sameBank(command); - satisfy_activateToActivate_differentBank(command); - satisfy_nActivateWindow(command); + delay_to_satisfy_activateToActivate_sameBank(command); + + while (!(state.bus.isFree(command.getStart()) && satsfies_activateToActivate_differentBank(command) && satisfies_nActivateWindow(command))) + { + command.delayStart(config.Timings.clk); + } - state.bus.moveCommandToNextFreeSlot(command); } sc_time ActivateChecker::getExecutionTime(const tlm::tlm_generic_payload& transaction, @@ -49,12 +51,7 @@ sc_time ActivateChecker::getExecutionTime(const tlm::tlm_generic_payload& transa return config.Timings.tRCD; } -void ActivateChecker::satisfy_activateToActivate_differentBank(ScheduledCommand& command) const -{ - state.activates.moveCommandToNextFreeSlot(command); -} - -void ActivateChecker::satisfy_activateToActivate_sameBank(ScheduledCommand& command) const +void ActivateChecker::delay_to_satisfy_activateToActivate_sameBank(ScheduledCommand& command) const { ScheduledCommand lastActivateOnBank = state.getLastCommand(Command::Activate, command.getBank()); @@ -64,13 +61,38 @@ void ActivateChecker::satisfy_activateToActivate_sameBank(ScheduledCommand& comm } } -void ActivateChecker::satisfy_nActivateWindow(ScheduledCommand& command) const +bool ActivateChecker::satsfies_activateToActivate_differentBank(ScheduledCommand& command) const { - if (!state.nActivateWindow.isFull()) - return; + for(sc_time time : state.lastActivates) + { + if((time < command.getStart() && command.getStart()-time= config.nActivate) + { + set lastActivates = state.lastActivates; + lastActivates.emplace(command.getStart()); + auto upper = lastActivates.begin(); + advance(upper, config.nActivate); + auto lower = lastActivates.begin(); + + while(upper != lastActivates.end()) + { + if(*upper-*lower < config.Timings.tTAW) + return false; + ++upper; + ++lower; + } + } + + return true; } } /* namespace controller */ diff --git a/dram/src/core/scheduling/checker/ActivateChecker.h b/dram/src/core/scheduling/checker/ActivateChecker.h index 8dabacb8..48a453c8 100644 --- a/dram/src/core/scheduling/checker/ActivateChecker.h +++ b/dram/src/core/scheduling/checker/ActivateChecker.h @@ -29,9 +29,9 @@ private: const Configuration& config; ControllerState& state;//TODO make const - void satisfy_activateToActivate_sameBank(ScheduledCommand& command) const; - void satisfy_activateToActivate_differentBank(ScheduledCommand& command) const; - void satisfy_nActivateWindow(ScheduledCommand& command) const; + void delay_to_satisfy_activateToActivate_sameBank(ScheduledCommand& command) const; + bool satsfies_activateToActivate_differentBank(ScheduledCommand& command) const; + bool satisfies_nActivateWindow(ScheduledCommand& command) const; }; } /* namespace controller */ diff --git a/dram/src/core/scheduling/checker/PrechargeChecker.cpp b/dram/src/core/scheduling/checker/PrechargeChecker.cpp index 72bd8a6d..b47b886a 100644 --- a/dram/src/core/scheduling/checker/PrechargeChecker.cpp +++ b/dram/src/core/scheduling/checker/PrechargeChecker.cpp @@ -26,7 +26,7 @@ void PrechargeChecker::delayToSatisfyConstraints(ScheduledCommand& command) cons } else if (lastCommand.getCommand() == Command::Write) { - command.delayToMeetConstraint(lastCommand.getStart(), lastCommand.getExecutionTime()); + command.delayToMeetConstraint(lastCommand.getEnd(), config.Timings.tWR); } else reportFatal("Precharge Checker", diff --git a/dram/src/core/scheduling/checker/PrechargeChecker.h b/dram/src/core/scheduling/checker/PrechargeChecker.h index 0c02ccad..aeff5eb8 100644 --- a/dram/src/core/scheduling/checker/PrechargeChecker.h +++ b/dram/src/core/scheduling/checker/PrechargeChecker.h @@ -24,7 +24,7 @@ public: virtual sc_time getExecutionTime(const tlm::tlm_generic_payload& payload, Command command) const override; private: const Configuration& config; - ControllerState& state;//TODO make const + ControllerState& state; }; } /* namespace controller */ diff --git a/dram/src/simulation/GroupPlayer.h b/dram/src/simulation/GroupPlayer.h new file mode 100644 index 00000000..97666b5e --- /dev/null +++ b/dram/src/simulation/GroupPlayer.h @@ -0,0 +1,160 @@ +/* + * GroupPlayer.h + * + * Created on: Apr 1, 2014 + * Author: robert + */ + +#ifndef GROUPPLAYER_H_ +#define GROUPPLAYER_H_ + +// +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include "MemoryManager.h" +//#include "../common/DebugManager.h" +//#include "../common/xmlAddressdecoder.h" +// +//using namespace std; +//using namespace tlm; +// +//template +//struct GroupedPlayer: public sc_module +//{ +//public: +// tlm_utils::simple_initiator_socket iSocket; +// +// GroupedPlayer(sc_module_name name, string pathToTrace,void (*callback_finished)(void), unsigned int senderNumber = 0) : +// payloadEventQueue(this, &GroupedPlayer::peqCallback), file(pathToTrace), numberOfPendingTransactions( +// 0), transactionsSent(0), senderNumber(senderNumber), callback_finished(callback_finished) +// { +// if (!file.is_open()) +// SC_REPORT_FATAL(0, (string("Could not open trace ") + pathToTrace).c_str()); +// +// if (!file) +// { +// SC_REPORT_FATAL(0, "trace is empty! Simulation stops"); +// } +// +// iSocket.register_nb_transport_bw(this, &GroupedPlayer::nb_transport_bw); +// +// scheduleNextPayload(); +// } +// +//private: +// tlm_utils::peq_with_cb_and_phase payloadEventQueue; +// MemoryManager memoryManager; +// ifstream file; +// unsigned int numberOfPendingTransactions; +// unsigned int transactionsSent; +// unsigned int senderNumber; +// void (*callback_finished)(void); +// +// void scheduleNextPayload() +// { +// string time, command, address; +// file >> time >> command >> address; +// +// long parsedAdress = std::stoi(address.c_str(), 0, 16); +// +// gp* payload = memoryManager.allocate(); +// payload->set_address(parsedAdress); +// +// if (command == "read") +// { +// payload->set_command(TLM_READ_COMMAND); +// } +// else if (command == "write") +// { +// payload->set_command(TLM_WRITE_COMMAND); +// } +// else +// { +// SC_REPORT_FATAL(0, +// (string("Corrupted tracefile, command ") + command + string(" unknown")).c_str()); +// } +// +// payload->set_data_length(BUSWIDTH / 8); +// payload->set_response_status(TLM_INCOMPLETE_RESPONSE); +// payload->set_dmi_allowed(false); +// payload->set_byte_enable_length(0); +// payload->set_streaming_width(0); +// +// sc_time sendingTime = sc_time(std::stoi(time.c_str()), SC_NS); +// if (sendingTime <= sc_time_stamp()) +// { +// payloadEventQueue.notify(*payload, BEGIN_REQ, SC_ZERO_TIME); +// } +// else +// { +// payloadEventQueue.notify(*payload, BEGIN_REQ, sendingTime - sc_time_stamp()); +// } +// numberOfPendingTransactions++; +// } +// +// tlm_sync_enum nb_transport_bw(tlm_generic_payload& payload, tlm_phase& phase, sc_time& bwDelay) +// { +// payloadEventQueue.notify(payload, phase, bwDelay); +// return TLM_ACCEPTED; +// } +// +// void peqCallback(tlm_generic_payload& payload, const tlm_phase& phase) +// { +// if (phase == BEGIN_REQ) +// { +// payload.acquire(); +// sendToTarget(payload, phase, SC_ZERO_TIME); +// transactionsSent++; +// DebugManager::getInstance().printDebugMessage( +// "Sending transaction number: " + std::to_string(transactionsSent), +// Sender::TracePlayer, senderNumber); +// } +// +// else if (phase == END_REQ) +// { +// scheduleNextPayload(); +// } +// else if (phase == BEGIN_RESP) +// { +// payload.release(); +// sendToTarget(payload, END_RESP, SC_ZERO_TIME); +// numberOfPendingTransactions--; +// +// DebugManager::getInstance().printDebugMessage( +// "Number of pending transactions: " +// + std::to_string(numberOfPendingTransactions), Sender::TracePlayer, +// senderNumber); +// if (numberOfPendingTransactions == 0) +// { +// callback_finished(); +//// cout << "simulation stop at " << sc_time_stamp() << std::endl; +//// sc_stop(); +// } +// } +// +// else if (phase == END_RESP) +// { +// } +// +// else +// { +// SC_REPORT_FATAL(0, "GroupedPlayer PEQ was triggered with unknown phase"); +// } +// } +// +// void sendToTarget(tlm_generic_payload& payload, const tlm_phase& phase, const sc_time& delay) +// { +// tlm_phase TPhase = phase; +// sc_time TDelay = delay; +// iSocket->nb_transport_fw(payload, TPhase, TDelay); +// } +//}; + + + +#endif /* GROUPPLAYER_H_ */ diff --git a/dram/src/simulation/arbiter.h b/dram/src/simulation/arbiter.h index d56b534d..1bba6133 100644 --- a/dram/src/simulation/arbiter.h +++ b/dram/src/simulation/arbiter.h @@ -9,7 +9,6 @@ #define ARBITER_H_ - #include #include #include @@ -96,7 +95,7 @@ private: else if (phase == END_REQ) { channelIsFree = true; - sendToTraceplayer(DramExtension::getExtension(payload).getThread().ID(), payload, phase, SC_ZERO_TIME); + sendToTraceplayer(DramExtension::getExtension(payload).getThread().ID()-1, payload, phase, SC_ZERO_TIME); if(!backpressure.empty()) { @@ -108,7 +107,7 @@ private: } else if (phase == BEGIN_RESP) { - sendToTraceplayer(DramExtension::getExtension(payload).getThread().ID(), payload, phase, SC_ZERO_TIME); + sendToTraceplayer(DramExtension::getExtension(payload).getThread().ID()-1, payload, phase, SC_ZERO_TIME); } else @@ -135,11 +134,12 @@ private: { node n; xmlAddressDecoder::getInstance().getNode(static_cast(payload.get_address()), &n); - DramExtension* extension = new DramExtension(Thread(socketId), Channel(n.channel), Bank(n.bank), Row(n.row), Column(n.colum)); + DramExtension* extension = new DramExtension(Thread(socketId+1), Channel(n.channel), Bank(n.bank), Row(n.row), Column(n.colum)); payload.set_auto_extension(extension); } }; + #endif /* ARBITER_H_ */ diff --git a/dram/src/simulation/main.cpp b/dram/src/simulation/main.cpp index e05a0dc0..51684f09 100644 --- a/dram/src/simulation/main.cpp +++ b/dram/src/simulation/main.cpp @@ -28,6 +28,17 @@ string pathOfFile(string file) return file.substr(0, file.find_last_of('/')); } +void endOfTrace_callback() +{ + static int finishedPlayers = 0; + finishedPlayers++; + if(finishedPlayers == 2) + { + + sc_stop(); + } +} + int sc_main(int argc, char **argv) { sc_set_time_resolution(1, SC_NS); @@ -35,19 +46,22 @@ int sc_main(int argc, char **argv) string resources = pathOfFile(argv[0]) + string("/../resources/"); xmlAddressDecoder::addressConfigURI = resources + string("configs/addressConfig.xml"); TlmRecorder recorder("tpr.tdb", resources + string("scripts/createTraceDB.sql")); - TracePlayer<> player("player", resources + string("traces/mediabench-fractal_32.stl")); - //TracePlayer<> player("player", resources + string("traces/mediabench-h263encode_32.stl")); + + TracePlayer<> player("player", resources + string("traces/mediabench-unepic_32.stl"),endOfTrace_callback, 0); + TracePlayer<> player2("player2", resources + string("traces/chstone-mips_32.stl"),endOfTrace_callback, 1); Dram<> dram("dram"); - Arbiter<> arbiter("arbiter"); + Arbiter<2,128> arbiter("arbiter"); ControllerWrapper<> controller("controller", recorder); + player.iSocket.bind(arbiter.tSockets[0]); + player2.iSocket.bind(arbiter.tSockets[1]); arbiter.iSocket.bind(controller.tSocket); controller.iSocket.bind(dram.tSocket); -// DebugManager::getInstance().addToWhiteList(Sender::TraceRecorder); -// DebugManager::getInstance().addToWhiteList(Sender::TracePlayer); + DebugManager::getInstance().addToWhiteList(Sender::TracePlayer); + //DebugManager::getInstance().addToWhiteList(Sender::TraceRecorder); //DebugManager::getInstance().addToWhiteList(Sender::DramWrapper); //DebugManager::getInstance().addToWhiteList(Sender::DramController); @@ -63,8 +77,6 @@ int sc_main(int argc, char **argv) string testingScript = resources + string("/scripts/tests.py"); string runTestCommand = string("python ") + testingScript + string(" tpr.tdb"); - //system(runTestCommand.c_str()); - string run_tpr = "/home/robert/analyzer/build/traceAnalyzer tpr.tdb"; system(run_tpr.c_str()); return 0; diff --git a/dram/src/simulation/traceplayer.h b/dram/src/simulation/traceplayer.h index 4a9ac641..83994548 100644 --- a/dram/src/simulation/traceplayer.h +++ b/dram/src/simulation/traceplayer.h @@ -8,8 +8,6 @@ #ifndef TRACEPLAYER_H_ #define TRACEPLAYER_H_ - - #include #include #include @@ -19,6 +17,7 @@ #include #include "MemoryManager.h" #include "../common/DebugManager.h" +#include "../common/xmlAddressdecoder.h" using namespace std; using namespace tlm; @@ -27,18 +26,18 @@ template struct TracePlayer: public sc_module { public: - tlm_utils::simple_initiator_socket iSocket; + tlm_utils::simple_initiator_socket iSocket; - TracePlayer(sc_module_name name, string pathToTrace) : - payloadEventQueue(this, &TracePlayer::peqCallback), file(pathToTrace), numberOfPendingTransactions(0), transactionsSent(0) + TracePlayer(sc_module_name name, string pathToTrace,void (*callback_finished)(void), unsigned int senderNumber = 0) : + payloadEventQueue(this, &TracePlayer::peqCallback), file(pathToTrace), numberOfPendingTransactions( + 0), transactionsSent(0), senderNumber(senderNumber), callback_finished(callback_finished) { if (!file.is_open()) SC_REPORT_FATAL(0, (string("Could not open trace ") + pathToTrace).c_str()); - if(!file) + if (!file) { SC_REPORT_FATAL(0, "trace is empty! Simulation stops"); - sc_stop(); } iSocket.register_nb_transport_bw(this, &TracePlayer::nb_transport_bw); @@ -51,54 +50,55 @@ private: ifstream file; unsigned int numberOfPendingTransactions; unsigned int transactionsSent; - + unsigned int senderNumber; + void (*callback_finished)(void); void scheduleNextPayload() { - if(file) + if (file) { - string time,command,address; - file >> time >> command >>address; + string time, command, address; + file >> time >> command >> address; //if there is a newline at the end of the .stl - if(time.empty() || command.empty() || address.empty()) + if (time.empty() || command.empty() || address.empty()) return; + long parsedAdress = std::stoi(address.c_str(), 0, 16); + gp* payload = memoryManager.allocate(); - long parsedAdress = std::stoi(address.c_str(),0,16); payload->set_address(parsedAdress); - if(command == "read") + if (command == "read") { payload->set_command(TLM_READ_COMMAND); } - else if(command == "write") + else if (command == "write") { payload->set_command(TLM_WRITE_COMMAND); } else { - SC_REPORT_FATAL(0, (string("Corrupted tracefile, command ") + command + string(" unknown")).c_str()); + SC_REPORT_FATAL(0, + (string("Corrupted tracefile, command ") + command + string(" unknown")).c_str()); } - - payload->set_data_length(BUSWIDTH/8); + payload->set_data_length(BUSWIDTH / 8); payload->set_response_status(TLM_INCOMPLETE_RESPONSE); payload->set_dmi_allowed(false); payload->set_byte_enable_length(0); payload->set_streaming_width(0); sc_time sendingTime = sc_time(std::stoi(time.c_str()), SC_NS); - if(sendingTime <= sc_time_stamp()) + if (sendingTime <= sc_time_stamp()) { - payloadEventQueue.notify(*payload,BEGIN_REQ,SC_ZERO_TIME); + payloadEventQueue.notify(*payload, BEGIN_REQ, SC_ZERO_TIME); } else { - payloadEventQueue.notify(*payload,BEGIN_REQ,sendingTime - sc_time_stamp()); + payloadEventQueue.notify(*payload, BEGIN_REQ, sendingTime - sc_time_stamp()); } numberOfPendingTransactions++; - } } @@ -108,15 +108,16 @@ private: return TLM_ACCEPTED; } - void peqCallback(tlm_generic_payload& payload, const tlm_phase& phase) { if (phase == BEGIN_REQ) { payload.acquire(); - sendToTarget(payload,phase,SC_ZERO_TIME); + sendToTarget(payload, phase, SC_ZERO_TIME); transactionsSent++; - DebugManager::getInstance().printDebugMessage("Sending transaction number: " + std::to_string(transactionsSent), Sender::TracePlayer); + DebugManager::getInstance().printDebugMessage( + "Sending transaction number: " + std::to_string(transactionsSent), + Sender::TracePlayer, senderNumber); } else if (phase == END_REQ) @@ -126,24 +127,28 @@ private: else if (phase == BEGIN_RESP) { payload.release(); - sendToTarget(payload,END_RESP,SC_ZERO_TIME); + sendToTarget(payload, END_RESP, SC_ZERO_TIME); numberOfPendingTransactions--; - DebugManager::getInstance().printDebugMessage("Number of pending transactions: " + std::to_string(numberOfPendingTransactions), Sender::TracePlayer); - if(numberOfPendingTransactions == 0) - payloadEventQueue.notify(payload, END_RESP, SC_ZERO_TIME); + DebugManager::getInstance().printDebugMessage( + "Number of pending transactions: " + + std::to_string(numberOfPendingTransactions), Sender::TracePlayer, + senderNumber); + if (numberOfPendingTransactions == 0) + { + callback_finished(); +// cout << "simulation stop at " << sc_time_stamp() << std::endl; +// sc_stop(); + } } - //kleiner hack else if (phase == END_RESP) { - cout << "simulation stop at " << sc_time_stamp() << std::endl; - sc_stop(); } else { - SC_REPORT_FATAL(0, "TracePlayer PEQ was triggered with unknown phase"); + SC_REPORT_FATAL(0, "TracePlayer PEQ was triggered with unknown phase"); } } @@ -155,7 +160,4 @@ private: } }; - - - #endif /* TRACEPLAYER_H_ */