Relocated the python scripts. They now live in the analyzer directory and are deployed to the output folder when building the analyzer.
Major change to simulation logic in dramSys: Commands in a transaction are now scheduled one at a time, instead of scheduling a whole transaction at once. Since single commands (e.g. Pre or Act) are not that long, refreshes are allowed to be delayed to allow a command to finsh. Consequently, the whole loop in the ControllerCore about trying to scheduleding a transaction and aborting it when it collides with a refresh could be ommitted. Lastly, Fifo_Strict has been added, which is a Fifo Scheduler that forces the read and write transactions, even between different banks to be executed in order. Fifo and FR_FCFS have been modified to fit into the new scheduling logic.
This commit is contained in:
@@ -4,11 +4,12 @@
|
||||
#include <iostream>
|
||||
#include <QFileInfo>
|
||||
#include <QDebug>
|
||||
#include <QApplication>
|
||||
|
||||
using namespace std;
|
||||
|
||||
PythonCaller::PythonCaller(const QString& pathToScripts) :
|
||||
testModuleName("tests"), testFunctionName("runTests"), metricModuleName("metrics"), metricFunctionName("calculateMetrics"), pathToScripts(pathToScripts.toStdString())
|
||||
PythonCaller::PythonCaller() :
|
||||
testModuleName("tests"), testFunctionName("runTests"), metricModuleName("metrics"), metricFunctionName("calculateMetrics"), pathToScripts(QApplication::applicationDirPath().toStdString() +"/scripts")
|
||||
{
|
||||
Py_Initialize();
|
||||
PyObject *sysPath = PySys_GetObject((char*)"path");
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
class PythonCaller
|
||||
{
|
||||
public:
|
||||
PythonCaller(const QString& pathToScripts);
|
||||
PythonCaller();
|
||||
~PythonCaller();
|
||||
TraceTestResults runTestsOnTrace(QString pathToTrace);
|
||||
TraceCalculatedMetrics calculateMetricsOnTrace(QString pathToTrace);
|
||||
@@ -18,7 +18,7 @@ private:
|
||||
PyObject *pRunTestsFunction, *pCalculateMetricsFunction;
|
||||
PyObject* loadFunctionFromModule(std::string moduleName, std::string functionName);
|
||||
std::string testModuleName, testFunctionName, metricModuleName, metricFunctionName, pathToScripts;
|
||||
PyObject *callFunctionWithStringArgument(PyObject *function, QString argument);
|
||||
PyObject *callFunctionWithStringArgument(PyObject *function, QString argument);
|
||||
};
|
||||
|
||||
#endif // PYTHONCALLER_H
|
||||
|
||||
@@ -83,9 +83,7 @@ void EvaluationTool::on_btn_test_clicked()
|
||||
|
||||
void EvaluationTool::runTests()
|
||||
{
|
||||
QString resourcesAbsPath = QApplication::applicationDirPath() + this->resourcesRelPath;
|
||||
qDebug() << resourcesAbsPath;
|
||||
PythonCaller pythonCaller(resourcesAbsPath);
|
||||
PythonCaller pythonCaller;
|
||||
ui->traceTestTreeWidget->clear();
|
||||
ui->testLight->setGray();
|
||||
|
||||
@@ -118,9 +116,7 @@ void EvaluationTool::on_btn_calculateMetrics_clicked()
|
||||
|
||||
void EvaluationTool::calculateMetrics()
|
||||
{
|
||||
QString resourcesAbsPath = QApplication::applicationDirPath() + this->resourcesRelPath;
|
||||
qDebug() << resourcesAbsPath;
|
||||
PythonCaller pythonCaller(resourcesAbsPath);
|
||||
PythonCaller pythonCaller;
|
||||
ui->traceMetricTreeWidget->clear();
|
||||
for(int row = 0; row < traceFilesModel->rowCount(); ++row)
|
||||
{
|
||||
|
||||
617
analyzer/analyzer/scripts/tests.py
Normal file
617
analyzer/analyzer/scripts/tests.py
Normal file
@@ -0,0 +1,617 @@
|
||||
import sys
|
||||
import traceback
|
||||
import sqlite3
|
||||
import os
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
def getPathToConfigs():
|
||||
return os.path.dirname(os.path.abspath(__file__).replace("/scripts","/configs"))
|
||||
|
||||
def getValueFromConfigXML(root, id):
|
||||
return root.findall(".//parameter[@id='{0}']".format(id))[0].attrib['value']
|
||||
|
||||
def getIntValueFromConfigXML(root, id):
|
||||
return int(root.findall(".//parameter[@id='{0}']".format(id))[0].attrib['value'])
|
||||
|
||||
def getMemconfig(connection):
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("SELECT Memconfig FROM GeneralInfo")
|
||||
result = cursor.fetchone()
|
||||
memconfig = result[0]
|
||||
return ET.parse(memconfig)
|
||||
|
||||
def getMemspec(connection):
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("SELECT Memspec FROM GeneralInfo")
|
||||
result = cursor.fetchone()
|
||||
memspec = result[0]
|
||||
return ET.parse(memspec)
|
||||
|
||||
def getClock(connection):
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("SELECT clk, UnitOfTime FROM GeneralInfo")
|
||||
result = cursor.fetchone()
|
||||
return (result[0],result[1])
|
||||
|
||||
class DramConfig(object):
|
||||
memoryType = ""
|
||||
bankwiseLogic = 0
|
||||
clk = 0
|
||||
unitOfTime = ""
|
||||
dataRate = 0
|
||||
nActivateWindow = numberOfBanks = 0
|
||||
|
||||
clk = 0
|
||||
tRP = 0 #precharge-time (pre -> act same bank)
|
||||
tRAS = 0 #active-time (act -> pre same bank)
|
||||
tRC = 0 #RAS-cycle-time (min time bw 2 succesive ACT to same bank)
|
||||
tCCD_S = 0 #TODO: relevant? max(bl, tCCD)
|
||||
tCCD_L = 0
|
||||
tRTP = 0 #Read to precharge
|
||||
tRRD_S = 0 #min time bw 2 succesive ACT to different banks (different bank group)
|
||||
tRRD_L = 0 #.. (same bank group)
|
||||
tRCD = 0 #act -> read/write
|
||||
tNAW = 0 #n activate window
|
||||
tRL = 0 #read latency (read command start to data strobe)
|
||||
tWL = 0 #write latency
|
||||
tWR = 0 #write recovery (write to precharge)
|
||||
tWTR_S = 0 #write to read (different bank group)
|
||||
tWTR_L = 0 #.. (same bank group)
|
||||
tCKESR = 0 #min time in sref
|
||||
tCKE = 0 #min time in pdna or pdnp
|
||||
tXP = 0 #min delay to row access command after pdnpx pdnax
|
||||
tXPDLL = 0 #min delay to row access command after pdnpx pdnax for dll commands
|
||||
tXSR = 0 #min delay to row access command after srefx
|
||||
tXSRDLL = 0 #min delay to row access command after srefx for dll commands
|
||||
tAL = 0 #additive delay (delayed execution in dram)
|
||||
tRFC = 0 #min ref->act delay
|
||||
|
||||
|
||||
def readConfigFromFiles(self, connection):
|
||||
print("Parsing dram configuration")
|
||||
memspec = getMemspec(connection)
|
||||
|
||||
clkWithUnit = getClock(connection)
|
||||
self.clk = clkWithUnit[0]
|
||||
self.unitOfTime = clkWithUnit[1].lower()
|
||||
|
||||
print(getMemconfig(connection))
|
||||
self.bankwiseLogic = getMemconfig(connection).findall("BankwiseLogic")[0].attrib['value']
|
||||
self.numberOfBanks = getIntValueFromConfigXML(memspec, "nbrOfBanks")
|
||||
self.burstLength = getIntValueFromConfigXML(memspec, "burstLength")
|
||||
self.memoryType = getValueFromConfigXML(memspec, "memoryType")
|
||||
self.dataRate = getIntValueFromConfigXML(memspec, "dataRate")
|
||||
|
||||
if(self.memoryType == "WIDEIO_SDR"):
|
||||
self.nActivateWindow = 2;
|
||||
self.tRP = self.clk * getIntValueFromConfigXML(memspec, "RP")
|
||||
self.tRAS = self.clk * getIntValueFromConfigXML(memspec, "RAS")
|
||||
self.tRC = self.clk * getIntValueFromConfigXML(memspec, "RC")
|
||||
self.tRRD_S = self.clk * getIntValueFromConfigXML(memspec, "RRD")
|
||||
self.tRRD_L = self.tRRD_S
|
||||
self.tCCD_S = self.clk * getIntValueFromConfigXML(memspec, "CCD")
|
||||
self.tCCD_L = self.tCCD_S
|
||||
self.tRCD = self.clk * getIntValueFromConfigXML(memspec, "RCD")
|
||||
self.tNAW = self.clk * getIntValueFromConfigXML(memspec, "TAW")
|
||||
self.tRL = self.clk * getIntValueFromConfigXML(memspec, "RL")
|
||||
self.tWL = self.clk * getIntValueFromConfigXML(memspec, "WL")
|
||||
self.tWR = self.clk * getIntValueFromConfigXML(memspec, "WR")
|
||||
self.tWTR_S = self.clk * getIntValueFromConfigXML(memspec, "WTR")
|
||||
self.tWTR_L = self.tWTR_S
|
||||
self.tRTP = self.clk * getIntValueFromConfigXML(memspec, "RTP");
|
||||
self.tCKESR = self.clk * getIntValueFromConfigXML(memspec, "CKESR")
|
||||
self.tCKE = self.clk * getIntValueFromConfigXML(memspec, "CKE")
|
||||
self.tXP = self.clk * getIntValueFromConfigXML(memspec, "XP")
|
||||
self.tXPDLL = self.tXP
|
||||
self.tXSR = self.clk * getIntValueFromConfigXML(memspec, "XS")
|
||||
self.tXSRDLL = self.tXSR
|
||||
self.tAL = self.clk * getIntValueFromConfigXML(memspec, "AL")
|
||||
self.tRFC = self.clk * getIntValueFromConfigXML(memspec, "RFC")
|
||||
|
||||
elif(self. memoryType == "DDR4"):
|
||||
self.nActivateWindow = 4;
|
||||
self.tRP = self.clk * getIntValueFromConfigXML(memspec, "RP");
|
||||
self.tRAS = self.clk * getIntValueFromConfigXML(memspec, "RAS");
|
||||
self.tRC = self.clk * getIntValueFromConfigXML(memspec, "RC");
|
||||
self.tRTP = self.clk * getIntValueFromConfigXML(memspec, "RTP");
|
||||
self.tRRD_S = self.clk * getIntValueFromConfigXML(memspec, "RRD_S");
|
||||
self.tRRD_L = self.clk * getIntValueFromConfigXML(memspec, "RRD_L");
|
||||
self.tCCD_S = self.clk * getIntValueFromConfigXML(memspec, "CCD_S");
|
||||
self.tCCD_L = self.clk * getIntValueFromConfigXML(memspec, "CCD_L");
|
||||
self.tRCD = self.clk * getIntValueFromConfigXML(memspec, "RCD");
|
||||
self.tNAW = self.clk * getIntValueFromConfigXML(memspec, "FAW");
|
||||
self.tRL = self.clk * getIntValueFromConfigXML(memspec, "RL");
|
||||
self.tWL = self.clk * getIntValueFromConfigXML(memspec, "WL");
|
||||
self.tWR = self.clk * getIntValueFromConfigXML(memspec, "WR");
|
||||
self.tWTR_S = self.clk * getIntValueFromConfigXML(memspec, "WTR_S");
|
||||
self.tWTR_L = self.clk * getIntValueFromConfigXML(memspec, "WTR_L");
|
||||
self.tCKESR = self.clk * getIntValueFromConfigXML(memspec, "CKESR");
|
||||
self.tCKE = self.clk * getIntValueFromConfigXML(memspec, "CKE");
|
||||
self.tXP = self.clk * getIntValueFromConfigXML(memspec, "XP");
|
||||
self.tXPDLL = self.clk * getIntValueFromConfigXML(memspec, "XPDLL");
|
||||
self.tXSR = self.clk * getIntValueFromConfigXML(memspec, "XS");
|
||||
self.tXSRDLL = self.clk * getIntValueFromConfigXML(memspec, "XSDLL");
|
||||
self.tAL = self.clk * getIntValueFromConfigXML(memspec, "AL");
|
||||
self.tRFC = self.clk * getIntValueFromConfigXML(memspec, "RFC");
|
||||
else:
|
||||
raise Exception("MemoryType not supported yet. Insert a coin into the coin machine and try again")
|
||||
|
||||
def clkAlign(self, value):
|
||||
return math.ceil(1.0*value/self.clk)*self.clk
|
||||
|
||||
def getWriteAccessTime(self):
|
||||
if(self.dataRate == 1):
|
||||
return self.clk*(self.burstLength - 1)
|
||||
elif (self.memoryType == "DDR4"):
|
||||
return self.clk*self.burstLength/self.dataRate
|
||||
|
||||
def getReadAccessTime(self):
|
||||
return self.burstLength/self.dataRate * dramconfig.clk
|
||||
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
dramconfig = DramConfig()
|
||||
|
||||
def calculateReadLength(burstLength):
|
||||
return dramconfig.tRL + burstLength * dramconfig.clk
|
||||
|
||||
def calculateWriteLength(burstLength):
|
||||
return dramconfig.tWL + burstLength * dramconfig.clk
|
||||
|
||||
# ----------- test utils ---------------------------------------
|
||||
|
||||
tests = []
|
||||
|
||||
def test(function):
|
||||
tests.append(function)
|
||||
return function
|
||||
|
||||
class TestResult(object):
|
||||
passed = True
|
||||
message = ''
|
||||
def __init__(self, passed = True, message = ''):
|
||||
self.passed = passed
|
||||
self.message = message
|
||||
|
||||
def TestSuceeded():
|
||||
return TestResult()
|
||||
|
||||
def TestFailed(message):
|
||||
return TestResult(False,message);
|
||||
|
||||
def formatTime(time):
|
||||
return ('{0} {1}'.format(time, dramconfig.unitOfTime))
|
||||
|
||||
# ----------- checks ---------------------------------------
|
||||
|
||||
@test
|
||||
def commands_are_clockaligned(connection):
|
||||
"""Checks that all commands on the command bus are aligned to the system clock"""
|
||||
|
||||
cursor = connection.cursor()
|
||||
query = "select ID,PhaseBegin,PhaseEnd from phases where phaseName NOT IN ('REQ','RESP') AND (phaseBegin%:clk!=0 OR phaseEnd%:clk!=0)"
|
||||
cursor.execute(query, {"clk": dramconfig.clk})
|
||||
|
||||
result = cursor.fetchone()
|
||||
|
||||
if(result != None):
|
||||
return TestFailed("Command with PhaseID {0} starts at {1} and ends at. One of those times. is not aligned to system clock ({2})"
|
||||
.format(result[0], formatTime(result[1]), formatTime(result[2]), formatTime(dramconfig.clk)))
|
||||
return TestSuceeded()
|
||||
|
||||
@test
|
||||
def commandbus_slots_are_used_once(connection):
|
||||
"""Checks that no two phases on the command bus start at the same time"""
|
||||
|
||||
cursor = connection.cursor()
|
||||
|
||||
if dramconfig.bankwiseLogic:
|
||||
excludedPhases = "('REQ','RESP','PRE_ALL')"
|
||||
else:
|
||||
excludedPhases = "('REQ','RESP','PRE_ALL','PDNA','PDNP','SREF','AUTO_REFRESH')"
|
||||
|
||||
query = """SELECT PhaseBegin,count FROM (SELECT phaseBegin,count(phasebegin) AS count
|
||||
FROM Phases WHERE PhaseName NOT IN """ + excludedPhases + """ AND phasebegin>0 GROUP BY phaseBegin) WHERE count>1"""
|
||||
|
||||
cursor.execute(query)
|
||||
result = cursor.fetchone()
|
||||
if(result != None):
|
||||
return TestFailed("Slot on commandbus at time {0} is used multiple times".format(formatTime(result[0])))
|
||||
return TestSuceeded()
|
||||
|
||||
|
||||
@test
|
||||
def phase_transitions_are_valid(connection):
|
||||
"""Checks that all transition of two consequtive phases on the same bank are valid"""
|
||||
|
||||
cursor = connection.cursor()
|
||||
validTransitions = {}
|
||||
|
||||
if(dramconfig.bankwiseLogic):
|
||||
validTransitions['PRE'] = set(['ACT', 'AUTO_REFRESH'])
|
||||
validTransitions['ACT'] = set(['RD', 'RDA', 'WR', 'WRA', 'PRE', 'PRE_ALL'])
|
||||
|
||||
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', 'PRE_ALl'])
|
||||
|
||||
validTransitions['RD'] = set(['PRE', 'PRE_ALL','RD','RDA', 'WR', 'WRA', 'PDNA'])
|
||||
validTransitions['WR'] = set(['PRE', 'PRE_ALL','RD','RDA', 'WR', 'WRA', 'PDNA'])
|
||||
validTransitions['RDA'] = set(['PRE_ALL', 'ACT', 'AUTO_REFRESH', 'PDNA', 'PDNP'])
|
||||
validTransitions['WRA'] = set(['PRE_ALL', 'ACT', 'AUTO_REFRESH', 'PDNA', 'PDNP'])
|
||||
|
||||
validTransitions['AUTO_REFRESH'] = set(['PRE_ALL', 'ACT','AUTO_REFRESH', 'PDNA', 'PDNP', 'SREF'])
|
||||
|
||||
validTransitions['PDNA'] = set(['PRE','PRE_ALL','ACT', 'RD', 'RDA', 'WR', 'WRA', 'AUTO_REFRESH', 'PDNA', 'PDNP'])
|
||||
validTransitions['PDNP'] = set(['PRE_ALL', 'ACT', 'AUTO_REFRESH', 'PDNA', 'PDNP'])
|
||||
validTransitions['SREF'] = set(['PRE_ALL', 'ACT', 'AUTO_REFRESH', 'PDNA', 'PDNP'])
|
||||
|
||||
|
||||
query = """SELECT PhaseName, phases.ID FROM phases INNER JOIN transactions ON phases.transact=transactions.ID WHERE TBank=:bank
|
||||
AND PhaseName NOT IN ('REQ','RESP') ORDER BY PhaseBegin"""
|
||||
|
||||
for bankNumber in range(dramconfig.numberOfBanks):
|
||||
cursor.execute(query, {"bank": bankNumber})
|
||||
lastRow = cursor.fetchone()
|
||||
for currentRow in cursor:
|
||||
currentPhase = currentRow[0]
|
||||
lastPhase = lastRow[0]
|
||||
if(currentPhase not in validTransitions[lastPhase]):
|
||||
return TestFailed("Phase {0}({1}) is not allowed to follow phase {2}({3})".format(currentRow[1],currentPhase,lastRow[1],lastPhase))
|
||||
lastRow = currentRow
|
||||
|
||||
return TestSuceeded()
|
||||
|
||||
|
||||
def timing_constraint(FirstPhase, SecondPhase):
|
||||
FirstPhaseName = FirstPhase[0]
|
||||
SecondPhaseName = SecondPhase[0]
|
||||
|
||||
if(FirstPhaseName == "PRE" or FirstPhaseName == "PRE_ALL"):
|
||||
return dramconfig.tRP
|
||||
|
||||
elif(FirstPhaseName == "ACT"):
|
||||
return dramconfig.tRCD
|
||||
|
||||
elif(FirstPhaseName == "RD"):
|
||||
if(SecondPhaseName in ["PRE, PRE_ALL"]):
|
||||
return dramconfig.tRTP
|
||||
elif(SecondPhaseName in ["RD, RDA"]):
|
||||
return max(dramconfig.tCCD_L, getReadAccessTime())
|
||||
elif(SecondPhase in ["WR","WRA"]):
|
||||
return dramconfig.tRL + getReadAccessTime() - dramconfig.tWL + 2*dramconfig.clk
|
||||
elif(SecondPhase == "PDNA" ):
|
||||
return dramconfig.tRL + getReadAccessTime() + dramconfig.clk
|
||||
|
||||
elif(FirstPhaseName == "WR"):
|
||||
if(SecondPhaseName in ["PRE, PRE_ALL", "PDNA"]):
|
||||
return dramconfig.tWL + dramconfig.getWriteAccessTime() + dramconfig.tWR
|
||||
elif(SecondPhaseName in ["RD, RDA"]):
|
||||
return dramconfig.tWL + dramconfig.getWriteAccessTime() + dramconfig.tWTR_L
|
||||
elif(SecondPhaseName in ["WR, WRA"]):
|
||||
return max(dramconfig.tCCD_L, burstlength/dramconfig.dataRate)
|
||||
|
||||
elif(FirstPhaseName == "RDA"):
|
||||
if(SecondPhaseName in ["ACT", "PRE_ALL", "AUTO_REFRESH"]):
|
||||
return dramconfig.tRTP + dramconfig.tRP
|
||||
elif(SecondPhaseName in ["PDNA","PDNP"]):
|
||||
return dramconfig.tRL + getReadAccessTime() + dramconfig.clk
|
||||
|
||||
elif(FirstPhaseName == "WRA"):
|
||||
if(SecondPhaseName in ["ACT", "PRE_ALL", "AUTO_REFRESH"]):
|
||||
return dramconfig.tWL + getWriteAccessTime() + dramconfig.tWR + dramconfig.tRP
|
||||
elif(SecondPhaseName in ["PDNA","PDNP"]):
|
||||
return dramconfig.tWL + dramconfig.getWriteAccessTime() + dramconfig.tWR + dramconfig.clk
|
||||
|
||||
elif(FirstPhaseName == "AUTO_REFRESH"):
|
||||
return dramconfig.tRFC
|
||||
|
||||
elif(FirstPhaseName in ["PDNA","PDNP"]):
|
||||
return (FirstPhase[3] - FirstPhase[2]) + dramconfig.tXP - dramconfig.clk
|
||||
|
||||
elif(FirstPhaseName == "SREF"):
|
||||
return (FirstPhase[3] - FirstPhase[2]) + dramconfig.tXSR - dramconfig.clk
|
||||
|
||||
return 0
|
||||
|
||||
@test
|
||||
def timing_constraits_on_the_same_bank_hold(connection):
|
||||
"""Checks that all transitions of two consequtive phases on the same bank meet their timing constraints"""
|
||||
cursor = connection.cursor()
|
||||
validTransitions = {}
|
||||
|
||||
query = """SELECT PhaseName, phases.ID,PhaseBegin,PhaseEnd FROM phases INNER JOIN transactions ON phases.transact=transactions.ID WHERE TBank=:bank
|
||||
AND PhaseName NOT IN ('REQ','RESP') ORDER BY PhaseBegin"""
|
||||
|
||||
for bankNumber in range(dramconfig.numberOfBanks):
|
||||
cursor.execute(query, {"bank": bankNumber})
|
||||
lastRow = cursor.fetchone()
|
||||
|
||||
for currentRow in cursor:
|
||||
constraint = timing_constraint(lastRow,currentRow)
|
||||
if(currentRow[2] - lastRow[2] + constraint < 0):
|
||||
return TestFailed("Phase {0}({1}) starts {2} after Start of Phase {3}({4}). Minimal time is {5}".format(
|
||||
currentRow[1],currentRow[0],formatTime(currentRow[2]-lastRow[2]),lastRow[1],lastRow[0], formatTime(constraint)))
|
||||
lastRow = currentRow
|
||||
return TestSuceeded()
|
||||
|
||||
@test
|
||||
def row_buffer_is_used_correctly(connection):
|
||||
"""Checks that each bank's row buffer is used correctly"""
|
||||
|
||||
cursor = connection.cursor()
|
||||
query = """SELECT PhaseName, phases.ID FROM phases INNER JOIN transactions ON phases.transact=transactions.ID WHERE TBank=:bank
|
||||
AND PhaseName NOT IN ('REQ','RESP') ORDER BY PhaseBegin"""
|
||||
|
||||
|
||||
#phases that precharge the bank and close the rowbuffer
|
||||
prechargingPhases = set(['PRE','PRE_ALL','RDA','WRA'])
|
||||
|
||||
#phases that require the bank to be in active state and the rowbuffer to be opened
|
||||
accessingPhases = set(['RD','RDA', 'WR', 'WRA', 'PRE'])
|
||||
|
||||
#phases that require the bank to be in precharged state and the robuffer to be closed
|
||||
idlePhases = set(['ACT', 'PDNP', 'AUTO_REFRESH', 'SREF'])
|
||||
|
||||
for bankNumber in range(dramconfig.numberOfBanks):
|
||||
cursor.execute(query,{"bank": bankNumber})
|
||||
|
||||
rowBufferIsClosed = True
|
||||
|
||||
|
||||
|
||||
for currentRow in cursor:
|
||||
if(currentRow[0] in accessingPhases and rowBufferIsClosed == True):
|
||||
return TestFailed("Phase {0}({1}) acesses a closed rowbuffer".format(currentRow[1], currentRow[0]))
|
||||
|
||||
if(currentRow[0] in idlePhases and rowBufferIsClosed == False):
|
||||
return TestFailed("Phase {0}({1}) needs a closed rowbuffer".format(currentRow[1], currentRow[0]))
|
||||
|
||||
if(currentRow[0] == 'ACT'):
|
||||
rowBufferIsClosed = False
|
||||
|
||||
if(currentRow[0] in prechargingPhases):
|
||||
rowBufferIsClosed = True
|
||||
|
||||
return TestSuceeded()
|
||||
|
||||
#----------- activate checks ---------------------------------------
|
||||
@test
|
||||
def activate_to_activate_holds(connection):
|
||||
"""Checks that all activates are far enough apart(JESD229 229, P. 27)"""
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("SELECT phases.ID,PhaseBegin,TBankGroup FROM Phases INNER JOIN transactions ON phases.transact=transactions.ID WHERE PhaseName = 'ACT' ORDER BY PhaseBegin")
|
||||
lastRow = cursor.fetchone()
|
||||
|
||||
for currentRow in cursor:
|
||||
timeBetweenActivates = currentRow[1] - lastRow[1]
|
||||
if (currentRow[2] == lastRow[2]):
|
||||
minTime = dramconfig.tRRD_L
|
||||
else:
|
||||
minTime = dramconfig.tRRD_S
|
||||
if(timeBetweenActivates < minTime):
|
||||
return TestFailed("Activates with PhaseIDs {0} and {1} are {2} apart. Minimum time between two activates is {3}".
|
||||
format(currentRow[0], lastRow[0],formatTime(timeBetweenActivates), formatTime(minTime)))
|
||||
|
||||
lastRow = currentRow
|
||||
|
||||
return TestSuceeded()
|
||||
|
||||
|
||||
@test
|
||||
def activate_to_activate_on_same_bank_holds(connection):
|
||||
"""Checks that all activates on the same bank are far enough apart (JEDEC 229, P. 27)"""
|
||||
cursor = connection.cursor()
|
||||
query = "SELECT Phases.ID,PhaseBegin from Phases INNER JOIN Transactions ON Phases.Transact = Transactions.ID WHERE PhaseName = 'ACT' AND TBANK = :bank ORDER BY PhaseBegin"
|
||||
|
||||
for bankNumber in range(dramconfig.numberOfBanks):
|
||||
cursor.execute(query,{"bank": bankNumber})
|
||||
lastRow = cursor.fetchone()
|
||||
|
||||
for currentRow in cursor:
|
||||
timeBetweenActivates = currentRow[1] - lastRow[1];
|
||||
if(timeBetweenActivates < dramconfig.tRC):
|
||||
return TestFailed("Activates with PhaseIDs {0} and {1} are {2} apart. Minimum time between two activates is {3}, since they are on the same bank({4})".
|
||||
format(currentRow[0], lastRow[0],formatTime(timeBetweenActivates), dramconfig.tRC))
|
||||
else:
|
||||
lastRow = currentRow
|
||||
|
||||
return TestSuceeded()
|
||||
|
||||
@test
|
||||
def n_activate_window_holds(connection):
|
||||
"""Checks that the n-Activate constraint is met everywhere(JEDEC 229, P. 27)"""
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("SELECT ID,PhaseBegin from Phases WHERE PhaseName = 'ACT' ORDER BY PhaseBegin")
|
||||
activateWindow = []
|
||||
|
||||
for currentRow in cursor:
|
||||
activateWindow.append(currentRow[1])
|
||||
if(len(activateWindow) > dramconfig.nActivateWindow + 1):
|
||||
activateWindow.pop(0)
|
||||
if(activateWindow[dramconfig.nActivateWindow] - activateWindow[0] < dramconfig.tNAW):
|
||||
return TestFailed("Activate with PhaseID {0} and the {1} preceeding activates violate the '{1} activate window' constraint."
|
||||
" No more than {1} activates should be in rolling time window of {2}".format(currentRow[0], dramconfig.nActivateWindow,formatTime(dramconfig.tNAW)))
|
||||
return TestSuceeded()
|
||||
|
||||
|
||||
# ----------- read/write checks ---------------------------------------
|
||||
@test
|
||||
def read_to_read_holds(connection):
|
||||
"""Check that the read operations do not intefere with each other on the data bus"""
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("SELECT phases.ID,PhaseBegin,TBankGroup FROM Phases INNER JOIN transactions ON phases.transact=transactions.ID WHERE PhaseName IN ('RD','RDA') ORDER BY PhaseBegin")
|
||||
lastRow = cursor.fetchone()
|
||||
|
||||
for currentRow in cursor:
|
||||
timeBetweenReads = currentRow[1] - lastRow[1]
|
||||
if (currentRow[2] == lastRow[2]):
|
||||
minTime = max(dramconfig.tCCD_L,dramconfig.getReadAccessTime())
|
||||
else:
|
||||
minTime = max(dramconfig.tCCD_S,dramconfig.getReadAccessTime())
|
||||
if(timeBetweenReads < minTime):
|
||||
return TestFailed("Reads with PhaseIDs {0} and {1} are {2} apart. Minimum time between two reads is {3}".format(currentRow[0], lastRow[0],formatTime(timeBetweenReads), minTime))
|
||||
lastRow = currentRow
|
||||
|
||||
return TestSuceeded()
|
||||
|
||||
|
||||
@test
|
||||
def write_to_write_holds(connection):
|
||||
"""Check that the write operations do not intefere with each other on the data bus"""
|
||||
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("SELECT phases.ID,PhaseBegin,TBankGroup FROM Phases INNER JOIN transactions ON phases.transact=transactions.ID WHERE PhaseName IN ('WR','WRA') ORDER BY PhaseBegin")
|
||||
lastRow = cursor.fetchone()
|
||||
|
||||
for currentRow in cursor:
|
||||
timeBetweenWrites = currentRow[1] - lastRow[1]
|
||||
if (currentRow[2] == lastRow[2]):
|
||||
minTime = max(dramconfig.tCCD_L,dramconfig.getWriteAccessTime())
|
||||
else:
|
||||
minTime = max(dramconfig.tCCD_S,dramconfig.getWriteAccessTime())
|
||||
if(timeBetweenWrites < minTime):
|
||||
return TestFailed("Writes with PhaseIDs {0} and {1} are {2} apart. Minimum time between two writes is {3}".format(currentRow[0], lastRow[0],formatTime(timeBetweenWrites), minTime))
|
||||
lastRow = currentRow
|
||||
return TestSuceeded()
|
||||
|
||||
@test
|
||||
def write_to_read_and_read_to_write_hold(connection):
|
||||
"""Checks that read and write operation do not interfere with each other on the data bus
|
||||
and that the write-to-read constraint is met"""
|
||||
|
||||
cursor = connection.cursor()
|
||||
query = """SELECT Phases.ID,PhaseBegin,PhaseName,TBankGroup from Phases INNER JOIN Transactions ON Phases.Transact = Transactions.ID
|
||||
WHERE PhaseName IN ('RD','WR','RDA','WRA') ORDER BY PhaseBegin"""
|
||||
|
||||
cursor.execute(query)
|
||||
lastRow = cursor.fetchone()
|
||||
|
||||
for currentRow in cursor:
|
||||
|
||||
if(currentRow[2] in ["RD","RDA"] and lastRow[2] in ["WR","WRA"]):
|
||||
#write to read
|
||||
if (currentRow[3] == lastRow[3]):
|
||||
tWTR = dramconfig.tWTR_L
|
||||
else:
|
||||
tWTR = dramconfig.tWTR_S
|
||||
|
||||
minWriteToRead = dramconfig.tWL + dramconfig.getWriteAccessTime() + tWTR
|
||||
writeToRead = currentRow[1] - lastRow[1]
|
||||
|
||||
if(writeToRead < minWriteToRead ):
|
||||
return TestFailed("Read {0} starts {1} after start of write {2}. Minimum time is {3}".
|
||||
format(currentRow[0],formatTime(writeToRead),lastRow[0], formatTime(minWriteToRead)))
|
||||
|
||||
elif(currentRow[2] in ["WR","WRA"] and lastRow[2] in ["RD","RDA"]):
|
||||
#read to write
|
||||
minReadToWrite = dramconfig.tRL + dramconfig.getReadAccessTime() - dramconfig.tWL + dramconfig.clk * 2
|
||||
readToWrite = currentRow[1] - lastRow[1]
|
||||
if(readToWrite < minReadToWrite ):
|
||||
return TestFailed("Write {0} starts {1} after start of read {2}. Minimum time is {3}".
|
||||
format(currentRow[0],formatTime(readToWrite),lastRow[0], formatTime(minWriteToRead)))
|
||||
|
||||
lastRow = currentRow
|
||||
|
||||
return TestSuceeded()
|
||||
|
||||
|
||||
@test
|
||||
def read_holds_dll_constraint_after_sref(connection):
|
||||
"""Checks that all read operations are delayed long enough after the end of the self refresh powerdown state"""
|
||||
|
||||
cursor = connection.cursor()
|
||||
query = """SELECT Phases.ID,PhaseBegin,PhaseName,TBankGroup from Phases INNER JOIN Transactions ON Phases.Transact = Transactions.ID AND TBank = :bank
|
||||
WHERE PhaseName IN ('RD', 'RDA', 'SREF') ORDER BY PhaseBegin"""
|
||||
|
||||
|
||||
for bankNumber in range(dramconfig.numberOfBanks):
|
||||
cursor.execute(query,{"bank": bankNumber})
|
||||
lastRow = cursor.fetchone()
|
||||
for currentRow in cursor:
|
||||
if(currentRow[2] in ["RD","RDA"] and lastRow[2] == 'SREF'):
|
||||
srefEndToRead = currentRow[1] - (lastRow[1] - dramconfig.clk)
|
||||
if(srefEndToRead < dramconfig.tXSRDLL ):
|
||||
return TestFailed("Read {0} starts {1} after end of sref {2}. Minimum time is {3}".
|
||||
format(currentRow[0],formatTime(srefEndToRead),lastRow[0], formatTime(dramconfig.tXSRDLL)))
|
||||
lastRow = currentRow
|
||||
return TestSuceeded()
|
||||
|
||||
# ----------- powerdown checks ---------------------------------------
|
||||
|
||||
# @test
|
||||
# def sref_active_for_minimal_time(connection):
|
||||
# """Checks that after entering self refresh powerndown state, the state is active for a minimal time (JEDEC 229, P. 41)"""
|
||||
#
|
||||
# cursor = connection.cursor()
|
||||
# cursor.execute("SELECT ID, PhaseEnd-clk-PhaseBegin FROM Phases, GeneralInfo WHERE PhaseName = 'SREF'")
|
||||
# for currentRow in cursor:
|
||||
# if(currentRow[1] < dramconfig.tCKESR):
|
||||
# return TestFailed("SREF with ID {0} is {1} long. Minimal time in SREF is {2}".format(currentRow[0], formatTime(currentRow[1]), dramconfig.tCKESR))
|
||||
# return TestSuceeded()
|
||||
|
||||
# @test
|
||||
# def pdna_pdnp_active_for_minimal_time(connection):
|
||||
# """Checks that after entering active/precharged powerdown, the state is active for a minimal time (JEDEC 229, P. 41)"""
|
||||
#
|
||||
# cursor = connection.cursor()
|
||||
# cursor.execute("SELECT ID,PhaseName, PhaseEnd-PhaseBegin FROM Phases, GeneralInfo WHERE PhaseName IN ('PDNA', 'PDNP') ")
|
||||
# for currentRow in cursor:
|
||||
# if(currentRow[2] < dramconfig.tCKE):
|
||||
# return TestFailed("{0} with ID {1} is {2} long. Minimal time in SREF is {3}".format(currentRow[1], currentRow[0], formatTime(currentRow[2]), dramconfig.tCKE))
|
||||
# return TestSuceeded()
|
||||
|
||||
# -------------------------- interface methods --------------------
|
||||
|
||||
def runTests(pathToTrace):
|
||||
connection = sqlite3.connect(pathToTrace)
|
||||
dramconfig.readConfigFromFiles(connection)
|
||||
|
||||
testResults = []
|
||||
numberOfFailedTest = 0
|
||||
print("================================")
|
||||
print("RUNNING TEST ON {0}".format(pathToTrace))
|
||||
|
||||
print("-----------------------------\n")
|
||||
|
||||
for test in tests:
|
||||
testResult = test(connection)
|
||||
testName = test.__name__.replace("_"," ")
|
||||
testResults.append((testName, testResult.passed,testResult.message))
|
||||
|
||||
if(testResult.passed):
|
||||
print("[passed] {0}".format(testName))
|
||||
else:
|
||||
print("[failed] {0} failed. Message: {1}".format(testName, testResult.message))
|
||||
numberOfFailedTest = numberOfFailedTest + 1
|
||||
|
||||
print("\n-----------------------------")
|
||||
|
||||
if(numberOfFailedTest == 0):
|
||||
print("All tests passed")
|
||||
else:
|
||||
print("{0} of {1} tests passed".format(len(tests) - numberOfFailedTest,len(tests)))
|
||||
|
||||
print("================================")
|
||||
connection.close()
|
||||
|
||||
return testResults
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w')
|
||||
for i in range(1,len(sys.argv)):
|
||||
runTests(sys.argv[i])
|
||||
|
||||
@@ -16,6 +16,11 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
TARGET = traceAnalyzer
|
||||
TEMPLATE = app
|
||||
|
||||
#copy python scripts
|
||||
config.path = $${OUT_PWD}/scripts
|
||||
config.files = scripts/*
|
||||
INSTALLS += config
|
||||
|
||||
SOURCES += main.cpp\
|
||||
businessObjects/transaction.cpp \
|
||||
businessObjects/timespan.cpp \
|
||||
@@ -95,7 +100,11 @@ FORMS += \
|
||||
evaluationtool.ui
|
||||
|
||||
OTHER_FILES += \
|
||||
common/static/createTraceDB.sql
|
||||
common/static/createTraceDB.sql \
|
||||
tests.py \
|
||||
metrics.py \
|
||||
scripts/metrics.py \
|
||||
scripts/tests.py
|
||||
|
||||
QMAKE_CXXFLAGS += -std=c++11
|
||||
QMAKE_CXXFLAGS += -Xlinker -export-dynamic
|
||||
|
||||
@@ -57,22 +57,22 @@ SOURCES += \
|
||||
../src/controller/core/scheduling/checker/PowerDownChecker.cpp \
|
||||
../src/controller/core/scheduling/checker/ActivateChecker.cpp \
|
||||
../src/controller/core/scheduling/ScheduledCommand.cpp \
|
||||
../src/controller/core/scheduling/CommandSequenceScheduler.cpp \
|
||||
../src/controller/core/scheduling/CommandSequenceGenerator.cpp \
|
||||
../src/controller/core/TimingCalculation.cpp \
|
||||
../src/controller/core/Slots.cpp \
|
||||
../src/controller/core/ControllerState.cpp \
|
||||
../src/controller/core/ControllerCore.cpp \
|
||||
../src/controller/core/Command.cpp \
|
||||
../src/simulation/SimulationManager.cpp \
|
||||
../src/simulation/Simulation.cpp \
|
||||
../src/simulation/MemoryManager.cpp \
|
||||
../src/simulation/main.cpp \
|
||||
../src/controller/core/RowBufferStates.cpp \
|
||||
../src/controller/scheduler/Scheduler.cpp \
|
||||
../src/controller/scheduler/readwritegrouper.cpp \
|
||||
../src/controller/core/configuration/ConfigurationLoader.cpp \
|
||||
../src/controller/core/powerdown/NoPowerDown.cpp
|
||||
../src/controller/core/powerdown/NoPowerDown.cpp \
|
||||
../src/controller/Command.cpp \
|
||||
../src/controller/Controller.cpp \
|
||||
../src/controller/ControllerState.cpp \
|
||||
../src/controller/RowBufferStates.cpp \
|
||||
../src/controller/scheduler/IScheduler.cpp \
|
||||
../src/controller/scheduler/FifoStrict.cpp
|
||||
|
||||
HEADERS += \
|
||||
../src/common/third_party/tinyxml2.h \
|
||||
@@ -88,7 +88,6 @@ HEADERS += \
|
||||
../src/controller/core/powerdown/PowerDownManagerBankwise.h \
|
||||
../src/controller/core/powerdown/PowerDownManager.h \
|
||||
../src/controller/scheduler/ThreadLoad.h \
|
||||
../src/controller/scheduler/Scheduler.h \
|
||||
../src/controller/scheduler/PARBS.h \
|
||||
../src/controller/scheduler/Fr_Fcfs.h \
|
||||
../src/controller/scheduler/Fifo.h \
|
||||
@@ -106,15 +105,9 @@ HEADERS += \
|
||||
../src/controller/core/scheduling/checker/ActivateChecker.h \
|
||||
../src/controller/core/scheduling/Trigger.h \
|
||||
../src/controller/core/scheduling/ScheduledCommand.h \
|
||||
../src/controller/core/scheduling/CommandSequenceScheduler.h \
|
||||
../src/controller/core/scheduling/CommandSequenceGenerator.h \
|
||||
../src/controller/core/scheduling/CommandSchedule.h \
|
||||
../src/controller/core/TimingCalculation.h \
|
||||
../src/controller/core/Slots.h \
|
||||
../src/controller/core/IWrapperConnector.h \
|
||||
../src/controller/core/ControllerState.h \
|
||||
../src/controller/core/ControllerCore.h \
|
||||
../src/controller/core/Command.h \
|
||||
../src/simulation/TracePlayer.h \
|
||||
../src/simulation/SimulationManager.h \
|
||||
../src/simulation/Simulation.h \
|
||||
@@ -122,13 +115,19 @@ HEADERS += \
|
||||
../src/simulation/Dram.h \
|
||||
../src/simulation/Arbiter.h \
|
||||
../src/common/libDRAMPower.h \
|
||||
../src/controller/core/RowBufferStates.h \
|
||||
../src/controller/scheduler/readwritegrouper.h \
|
||||
../src/simulation/ReorderBuffer.h \
|
||||
../src/controller/core/configuration/MemSpec.h \
|
||||
../src/simulation/StlPlayer.h \
|
||||
../src/simulation/TracePlayerListener.h \
|
||||
../src/simulation/TraceGenerator.h \
|
||||
../src/controller/core/powerdown/NoPowerDown.h
|
||||
../src/controller/core/powerdown/NoPowerDown.h \
|
||||
../src/controller/Command.h \
|
||||
../src/controller/RowBufferStates.h \
|
||||
../src/controller/ControllerState.h \
|
||||
../src/controller/core/powerdown/IPowerDownManager.h \
|
||||
../src/controller/scheduler/IScheduler.h \
|
||||
../src/controller/scheduler/FifoStrict.h \
|
||||
../src/controller/IController.h
|
||||
../src/controller/core/configuration/ConfigurationLoader.h
|
||||
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
<memconfig>
|
||||
<BankwiseLogic value="0"/>
|
||||
<OpenPagePolicy value="1" />
|
||||
<AdaptiveOpenPagePolicy value="0" />
|
||||
<RefreshAwareScheduling value="1" />
|
||||
<MaxNrOfTransactions value="50" />
|
||||
<Scheduler value="FIFO" />
|
||||
<Capsize value="5" />
|
||||
<PowerDownMode value="Staggered" />
|
||||
<PowerDownMode value="TimeoutPDN" />
|
||||
<PowerDownTimeout value="100" />
|
||||
</memconfig>
|
||||
</memconfig>
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
<memconfig>
|
||||
<BankwiseLogic value="0"/>
|
||||
<OpenPagePolicy value="1" />
|
||||
<AdaptiveOpenPagePolicy value="0" />
|
||||
<RefreshAwareScheduling value="1" />
|
||||
<MaxNrOfTransactions value="50" />
|
||||
<Scheduler value="FR_FCFS" />
|
||||
<Capsize value="5" />
|
||||
<PowerDownMode value="NoPowerDown" />
|
||||
<PowerDownMode value="TimeoutPDN" />
|
||||
<PowerDownTimeout value="100" />
|
||||
<!--
|
||||
<Buswidth value="128" />
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
import stlGenerator
|
||||
|
||||
stlGenerator = stlGenerator.StlGenerator()
|
||||
|
||||
|
||||
def simple_frfcfs():
|
||||
stlGenerator.clear()
|
||||
stlGenerator.addAction(0, 0)
|
||||
stlGenerator.addAction(0, 1)
|
||||
stlGenerator.addAction(2, 0)
|
||||
stlGenerator.addAction(3, 0)
|
||||
stlGenerator.addAction(4, 0)
|
||||
stlGenerator.addAction(5, 0)
|
||||
stlGenerator.generateStl('../traces/test2.stl')
|
||||
|
||||
if __name__ == '__main__':
|
||||
simple_frfcfs();
|
||||
@@ -1,123 +0,0 @@
|
||||
import xml.etree.ElementTree as ET
|
||||
import re
|
||||
import sys
|
||||
import os
|
||||
|
||||
|
||||
class DramConfigReader:
|
||||
maxValues = {}
|
||||
startBits = {}
|
||||
endBits = {}
|
||||
|
||||
def __extractAdressEncoding(self, root, elementName):
|
||||
rowElement = root[0].find(elementName)
|
||||
rowBitFrom, rowBitsTo = int(
|
||||
rowElement.attrib['from']), int(rowElement.attrib['to'])
|
||||
rowBitRange = rowBitsTo - rowBitFrom + 1
|
||||
maxRow = 2 ** rowBitRange - 1
|
||||
print('{0}: range {1}..{2}'.format(elementName, 0, maxRow))
|
||||
self.startBits[elementName] = rowBitFrom
|
||||
self.endBits[elementName] = rowBitsTo
|
||||
self.maxValues[elementName] = maxRow
|
||||
|
||||
def __init__(self):
|
||||
root = ET.parse(
|
||||
os.path.dirname(os.path.realpath(sys.argv[0])) + '/../configs/addressConfig.xml').getroot()
|
||||
self.__extractAdressEncoding(root, 'channel')
|
||||
self.__extractAdressEncoding(root, 'bank')
|
||||
self.__extractAdressEncoding(root, 'row')
|
||||
self.__extractAdressEncoding(root, 'colum')
|
||||
print(self.startBits)
|
||||
print(self.endBits)
|
||||
|
||||
class StlReader:
|
||||
# __dramConfigReader = DramConfigReader()
|
||||
|
||||
# def onesMask(self, numberOfOnes):
|
||||
# result = 0
|
||||
# for i in range(numberOfOnes):
|
||||
# result = result | 1 << i
|
||||
# return result
|
||||
|
||||
# def parseAttributeFromAddress(self, address, element):
|
||||
# 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: {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 ''
|
||||
|
||||
def printStlPretty(self, filename):
|
||||
f = open(filename)
|
||||
for line in f.readlines():
|
||||
#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
|
||||
# __dramConfigReader = DramConfigReader()
|
||||
|
||||
# def clear(self):
|
||||
# self.__actions = []
|
||||
# self.__time = 0
|
||||
|
||||
# def setTime(self, time):
|
||||
# self.__time = time
|
||||
|
||||
# def addAction(self, bank, row, channel=0, RD_WR='read'):
|
||||
# tupel = (self.__time, RD_WR, self.__generateAdress(channel, bank, row))
|
||||
# self.__actions.append(tupel)
|
||||
|
||||
# def setTimeAndAddAction(self, time, bank, row, channel=0, RD_WR='read'):
|
||||
# self.setTime(self, time)
|
||||
# self.addAction(self, bank, row, channel, RD_WR)
|
||||
|
||||
# def addLoad(self, banks, rows, channel=0, RD_WR='read'):
|
||||
# for bank in banks:
|
||||
# for row in rows:
|
||||
# self.addAction(bank, row, channel, RD_WR)
|
||||
|
||||
# def setTimeAndAddLoad(self, time, banks, rows, channel=0, RD_WR='read'):
|
||||
# self.setTime(self, time)
|
||||
# self.addLoad(banks, rows, channel, RD_WR)
|
||||
|
||||
# def generateStl(self, filename):
|
||||
# f = open(filename, 'w')
|
||||
# tmp = []
|
||||
# for tupel in self.__actions:
|
||||
# tmp.append('{0}: {1} {2:#x}'.format(tupel[0], tupel[1], tupel[2]))
|
||||
# result = '\n'.join(tmp)
|
||||
# f.write(result)
|
||||
# f.close()
|
||||
# print(
|
||||
# '<---------------------- Generated stl {0} ---------------------->'.format(filename))
|
||||
# print(result)
|
||||
# print(
|
||||
# '<---------------------- End generated stl ---------------------->'.format(filename))
|
||||
|
||||
# def __generateAdress(self, channel, bank, row):
|
||||
# if(channel > self.__dramConfigReader.maxValues['channel']):
|
||||
# raise(BaseException('Channel argument out of range'))
|
||||
# if(bank > self.__dramConfigReader.maxValues['bank']):
|
||||
# raise(BaseException('Bank argument out of range'))
|
||||
# if(row > self.__dramConfigReader.maxValues['row']):
|
||||
# raise(BaseException('Row argument out of range'))
|
||||
# return (channel << self.__dramConfigReader.startBits['channel']) | (bank << self.__dramConfigReader.startBits['bank']) | (row << self.__dramConfigReader.startBits['row'])
|
||||
|
||||
# def __init__(self):
|
||||
# pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if(len(sys.argv) > 1):
|
||||
stlReader = StlReader()
|
||||
for line in sys.argv[1:]:
|
||||
stlReader.printStlPretty(line)
|
||||
@@ -1,617 +0,0 @@
|
||||
import sys
|
||||
import traceback
|
||||
import sqlite3
|
||||
import os
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
def getPathToConfigs():
|
||||
return os.path.dirname(os.path.abspath(__file__).replace("/scripts","/configs"))
|
||||
|
||||
def getValueFromConfigXML(root, id):
|
||||
return root.findall(".//parameter[@id='{0}']".format(id))[0].attrib['value']
|
||||
|
||||
def getIntValueFromConfigXML(root, id):
|
||||
return int(root.findall(".//parameter[@id='{0}']".format(id))[0].attrib['value'])
|
||||
|
||||
def getMemconfig(connection):
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("SELECT Memconfig FROM GeneralInfo")
|
||||
result = cursor.fetchone()
|
||||
memconfig = getPathToConfigs() + "/memconfigs/" + result[0]
|
||||
return ET.parse(memconfig)
|
||||
|
||||
def getMemspec(connection):
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("SELECT Memspec FROM GeneralInfo")
|
||||
result = cursor.fetchone()
|
||||
memspec = getPathToConfigs() + "/memspecs/" + result[0]
|
||||
return ET.parse(memspec)
|
||||
|
||||
def getClock(connection):
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("SELECT clk, UnitOfTime FROM GeneralInfo")
|
||||
result = cursor.fetchone()
|
||||
return (result[0],result[1])
|
||||
|
||||
class DramConfig(object):
|
||||
memoryType = ""
|
||||
bankwiseLogic = 0
|
||||
clk = 0
|
||||
unitOfTime = ""
|
||||
dataRate = 0
|
||||
nActivateWindow = numberOfBanks = 0
|
||||
|
||||
clk = 0
|
||||
tRP = 0 #precharge-time (pre -> act same bank)
|
||||
tRAS = 0 #active-time (act -> pre same bank)
|
||||
tRC = 0 #RAS-cycle-time (min time bw 2 succesive ACT to same bank)
|
||||
tCCD_S = 0 #TODO: relevant? max(bl, tCCD)
|
||||
tCCD_L = 0
|
||||
tRTP = 0 #Read to precharge
|
||||
tRRD_S = 0 #min time bw 2 succesive ACT to different banks (different bank group)
|
||||
tRRD_L = 0 #.. (same bank group)
|
||||
tRCD = 0 #act -> read/write
|
||||
tNAW = 0 #n activate window
|
||||
tRL = 0 #read latency (read command start to data strobe)
|
||||
tWL = 0 #write latency
|
||||
tWR = 0 #write recovery (write to precharge)
|
||||
tWTR_S = 0 #write to read (different bank group)
|
||||
tWTR_L = 0 #.. (same bank group)
|
||||
tCKESR = 0 #min time in sref
|
||||
tCKE = 0 #min time in pdna or pdnp
|
||||
tXP = 0 #min delay to row access command after pdnpx pdnax
|
||||
tXPDLL = 0 #min delay to row access command after pdnpx pdnax for dll commands
|
||||
tXSR = 0 #min delay to row access command after srefx
|
||||
tXSRDLL = 0 #min delay to row access command after srefx for dll commands
|
||||
tAL = 0 #additive delay (delayed execution in dram)
|
||||
tRFC = 0 #min ref->act delay
|
||||
|
||||
|
||||
def readConfigFromFiles(self, connection):
|
||||
print("Parsing dram configuration")
|
||||
memspec = getMemspec(connection)
|
||||
|
||||
clkWithUnit = getClock(connection)
|
||||
self.clk = clkWithUnit[0]
|
||||
self.unitOfTime = clkWithUnit[1].lower()
|
||||
|
||||
self.bankwiseLogic = getIntValueFromConfigXML(getMemconfig(connection), "bankwiseLogic")
|
||||
self.numberOfBanks = getIntValueFromConfigXML(memspec, "nbrOfBanks")
|
||||
self.burstLength = getIntValueFromConfigXML(memspec, "burstLength")
|
||||
self.memoryType = getValueFromConfigXML(memspec, "memoryType")
|
||||
self.dataRate = getIntValueFromConfigXML(memspec, "dataRate")
|
||||
|
||||
if(self.memoryType == "WIDEIO_SDR"):
|
||||
self.nActivateWindow = 2;
|
||||
self.tRP = self.clk * getIntValueFromConfigXML(memspec, "RP")
|
||||
self.tRAS = self.clk * getIntValueFromConfigXML(memspec, "RAS")
|
||||
self.tRC = self.clk * getIntValueFromConfigXML(memspec, "RC")
|
||||
self.tRRD_S = self.clk * getIntValueFromConfigXML(memspec, "RRD")
|
||||
self.tRRD_L = self.tRRD_S
|
||||
self.tCCD_S = self.clk * getIntValueFromConfigXML(memspec, "CCD")
|
||||
self.tCCD_L = self.tCCD_S
|
||||
self.tRCD = self.clk * getIntValueFromConfigXML(memspec, "RCD")
|
||||
self.tNAW = self.clk * getIntValueFromConfigXML(memspec, "TAW")
|
||||
self.tRL = self.clk * getIntValueFromConfigXML(memspec, "RL")
|
||||
self.tWL = self.clk * getIntValueFromConfigXML(memspec, "WL")
|
||||
self.tWR = self.clk * getIntValueFromConfigXML(memspec, "WR")
|
||||
self.tWTR_S = self.clk * getIntValueFromConfigXML(memspec, "WTR")
|
||||
self.tWTR_L = self.tWTR_S
|
||||
self.tRTP = self.clk * getIntValueFromConfigXML(memspec, "RTP");
|
||||
self.tCKESR = self.clk * getIntValueFromConfigXML(memspec, "CKESR")
|
||||
self.tCKE = self.clk * getIntValueFromConfigXML(memspec, "CKE")
|
||||
self.tXP = self.clk * getIntValueFromConfigXML(memspec, "XP")
|
||||
self.tXPDLL = self.tXP
|
||||
self.tXSR = self.clk * getIntValueFromConfigXML(memspec, "XS")
|
||||
self.tXSRDLL = self.tXSR
|
||||
self.tAL = self.clk * getIntValueFromConfigXML(memspec, "AL")
|
||||
self.tRFC = self.clk * getIntValueFromConfigXML(memspec, "RFC")
|
||||
|
||||
elif(self. memoryType == "DDR4"):
|
||||
self.nActivateWindow = 4;
|
||||
self.tRP = self.clk * getIntValueFromConfigXML(memspec, "RP");
|
||||
self.tRAS = self.clk * getIntValueFromConfigXML(memspec, "RAS");
|
||||
self.tRC = self.clk * getIntValueFromConfigXML(memspec, "RC");
|
||||
self.tRTP = self.clk * getIntValueFromConfigXML(memspec, "RTP");
|
||||
self.tRRD_S = self.clk * getIntValueFromConfigXML(memspec, "RRD_S");
|
||||
self.tRRD_L = self.clk * getIntValueFromConfigXML(memspec, "RRD_L");
|
||||
self.tCCD_S = self.clk * getIntValueFromConfigXML(memspec, "CCD_S");
|
||||
self.tCCD_L = self.clk * getIntValueFromConfigXML(memspec, "CCD_L");
|
||||
self.tRCD = self.clk * getIntValueFromConfigXML(memspec, "RCD");
|
||||
self.tNAW = self.clk * getIntValueFromConfigXML(memspec, "FAW");
|
||||
self.tRL = self.clk * getIntValueFromConfigXML(memspec, "RL");
|
||||
self.tWL = self.clk * getIntValueFromConfigXML(memspec, "WL");
|
||||
self.tWR = self.clk * getIntValueFromConfigXML(memspec, "WR");
|
||||
self.tWTR_S = self.clk * getIntValueFromConfigXML(memspec, "WTR_S");
|
||||
self.tWTR_L = self.clk * getIntValueFromConfigXML(memspec, "WTR_L");
|
||||
self.tCKESR = self.clk * getIntValueFromConfigXML(memspec, "CKESR");
|
||||
self.tCKE = self.clk * getIntValueFromConfigXML(memspec, "CKE");
|
||||
self.tXP = self.clk * getIntValueFromConfigXML(memspec, "XP");
|
||||
self.tXPDLL = self.clk * getIntValueFromConfigXML(memspec, "XPDLL");
|
||||
self.tXSR = self.clk * getIntValueFromConfigXML(memspec, "XS");
|
||||
self.tXSRDLL = self.clk * getIntValueFromConfigXML(memspec, "XSDLL");
|
||||
self.tAL = self.clk * getIntValueFromConfigXML(memspec, "AL");
|
||||
self.tRFC = self.clk * getIntValueFromConfigXML(memspec, "RFC");
|
||||
else:
|
||||
raise Exception("MemoryType not supported yet. Insert a coin into the coin machine and try again")
|
||||
|
||||
def clkAlign(self, value):
|
||||
return math.ceil(1.0*value/self.clk)*self.clk
|
||||
|
||||
def getWriteAccessTime(self):
|
||||
if(self.dataRate == 1):
|
||||
return self.clk*(self.burstLength - 1)
|
||||
elif (self.memoryType == "DDR4"):
|
||||
return self.clk*self.burstLength/self.dataRate
|
||||
|
||||
def getReadAccessTime(self):
|
||||
return self.burstLength/self.dataRate * dramconfig.clk
|
||||
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
dramconfig = DramConfig()
|
||||
|
||||
def calculateReadLength(burstLength):
|
||||
return dramconfig.tRL + burstLength * dramconfig.clk
|
||||
|
||||
def calculateWriteLength(burstLength):
|
||||
return dramconfig.tWL + burstLength * dramconfig.clk
|
||||
|
||||
# ----------- test utils ---------------------------------------
|
||||
|
||||
tests = []
|
||||
|
||||
def test(function):
|
||||
tests.append(function)
|
||||
return function
|
||||
|
||||
class TestResult(object):
|
||||
passed = True
|
||||
message = ''
|
||||
def __init__(self, passed = True, message = ''):
|
||||
self.passed = passed
|
||||
self.message = message
|
||||
|
||||
def TestSuceeded():
|
||||
return TestResult()
|
||||
|
||||
def TestFailed(message):
|
||||
return TestResult(False,message);
|
||||
|
||||
def formatTime(time):
|
||||
return ('{0} {1}'.format(time, dramconfig.unitOfTime))
|
||||
|
||||
# ----------- checks ---------------------------------------
|
||||
|
||||
@test
|
||||
def commands_are_clockaligned(connection):
|
||||
"""Checks that all commands on the command bus are aligned to the system clock"""
|
||||
|
||||
cursor = connection.cursor()
|
||||
query = "select ID,PhaseBegin,PhaseEnd from phases where phaseName NOT IN ('REQ','RESP') AND (phaseBegin%:clk!=0 OR phaseEnd%:clk!=0)"
|
||||
cursor.execute(query, {"clk": dramconfig.clk})
|
||||
|
||||
result = cursor.fetchone()
|
||||
|
||||
if(result != None):
|
||||
return TestFailed("Command with PhaseID {0} starts at {1} and ends at. One of those times. is not aligned to system clock ({2})"
|
||||
.format(result[0], formatTime(result[1]), formatTime(result[2]), formatTime(dramconfig.clk)))
|
||||
return TestSuceeded()
|
||||
|
||||
@test
|
||||
def commandbus_slots_are_used_once(connection):
|
||||
"""Checks that no two phases on the command bus start at the same time"""
|
||||
|
||||
cursor = connection.cursor()
|
||||
|
||||
if dramconfig.bankwiseLogic:
|
||||
excludedPhases = "('REQ','RESP','PRE_ALL')"
|
||||
else:
|
||||
excludedPhases = "('REQ','RESP','PRE_ALL','PDNA','PDNP','SREF','AUTO_REFRESH')"
|
||||
|
||||
query = """SELECT PhaseBegin,count FROM (SELECT phaseBegin,count(phasebegin) AS count
|
||||
FROM Phases WHERE PhaseName NOT IN """ + excludedPhases + """ AND phasebegin>0 GROUP BY phaseBegin) WHERE count>1"""
|
||||
|
||||
cursor.execute(query)
|
||||
result = cursor.fetchone()
|
||||
if(result != None):
|
||||
return TestFailed("Slot on commandbus at time {0} is used multiple times".format(formatTime(result[0])))
|
||||
return TestSuceeded()
|
||||
|
||||
|
||||
@test
|
||||
def phase_transitions_are_valid(connection):
|
||||
"""Checks that all transition of two consequtive phases on the same bank are valid"""
|
||||
|
||||
cursor = connection.cursor()
|
||||
validTransitions = {}
|
||||
|
||||
if(dramconfig.bankwiseLogic):
|
||||
validTransitions['PRE'] = set(['ACT', 'AUTO_REFRESH'])
|
||||
validTransitions['ACT'] = set(['RD', 'RDA', 'WR', 'WRA'])
|
||||
|
||||
validTransitions['RD'] = set(['PRE','RD','RDA', 'WR', 'WRA', 'PDNA'])
|
||||
validTransitions['WR'] = set(['PRE', 'RD','RDA', 'WR', 'WRA', 'PDNA'])
|
||||
validTransitions['RDA'] = set(['ACT', 'AUTO_REFRESH', 'PDNP'])
|
||||
validTransitions['WRA'] = set(['ACT', 'AUTO_REFRESH', 'PDNP'])
|
||||
|
||||
validTransitions['AUTO_REFRESH'] = set(['ACT', 'PDNP', 'SREF'])
|
||||
|
||||
validTransitions['PDNA'] = set(['PRE', 'RD','RDA', 'WR', 'WRA', 'AUTO_REFRESH'])
|
||||
validTransitions['PDNP'] = set(['ACT', 'AUTO_REFRESH'])
|
||||
validTransitions['SREF'] = set(['ACT'])
|
||||
else:
|
||||
validTransitions['PRE'] = set(['ACT'])
|
||||
validTransitions['PRE_ALL'] = set(['AUTO_REFRESH'])
|
||||
validTransitions['ACT'] = set(['RD', 'RDA', 'WR', 'WRA'])
|
||||
|
||||
validTransitions['RD'] = set(['PRE', 'PRE_ALL','RD','RDA', 'WR', 'WRA', 'PDNA'])
|
||||
validTransitions['WR'] = set(['PRE', 'PRE_ALL','RD','RDA', 'WR', 'WRA', 'PDNA'])
|
||||
validTransitions['RDA'] = set(['PRE_ALL', 'ACT', 'AUTO_REFRESH', 'PDNA', 'PDNP'])
|
||||
validTransitions['WRA'] = set(['PRE_ALL', 'ACT', 'AUTO_REFRESH', 'PDNA', 'PDNP'])
|
||||
|
||||
validTransitions['AUTO_REFRESH'] = set(['PRE_ALL', 'ACT','AUTO_REFRESH', 'PDNA', 'PDNP', 'SREF'])
|
||||
|
||||
validTransitions['PDNA'] = set(['PRE','PRE_ALL','ACT', 'RD', 'RDA', 'WR', 'WRA', 'AUTO_REFRESH', 'PDNA', 'PDNP'])
|
||||
validTransitions['PDNP'] = set(['PRE_ALL', 'ACT', 'AUTO_REFRESH', 'PDNA', 'PDNP'])
|
||||
validTransitions['SREF'] = set(['PRE_ALL', 'ACT', 'AUTO_REFRESH', 'PDNA', 'PDNP'])
|
||||
|
||||
|
||||
query = """SELECT PhaseName, phases.ID FROM phases INNER JOIN transactions ON phases.transact=transactions.ID WHERE TBank=:bank
|
||||
AND PhaseName NOT IN ('REQ','RESP') ORDER BY PhaseBegin"""
|
||||
|
||||
for bankNumber in range(dramconfig.numberOfBanks):
|
||||
cursor.execute(query, {"bank": bankNumber})
|
||||
lastRow = cursor.fetchone()
|
||||
for currentRow in cursor:
|
||||
currentPhase = currentRow[0]
|
||||
lastPhase = lastRow[0]
|
||||
if(currentPhase not in validTransitions[lastPhase]):
|
||||
return TestFailed("Phase {0}({1}) is not allowed to follow phase {2}({3})".format(currentRow[1],currentPhase,lastRow[1],lastPhase))
|
||||
lastRow = currentRow
|
||||
|
||||
return TestSuceeded()
|
||||
|
||||
|
||||
def timing_constraint(FirstPhase, SecondPhase):
|
||||
FirstPhaseName = FirstPhase[0]
|
||||
SecondPhaseName = SecondPhase[0]
|
||||
|
||||
if(FirstPhaseName == "PRE" or FirstPhaseName == "PRE_ALL"):
|
||||
return dramconfig.tRP
|
||||
|
||||
elif(FirstPhaseName == "ACT"):
|
||||
return dramconfig.tRCD
|
||||
|
||||
elif(FirstPhaseName == "RD"):
|
||||
if(SecondPhaseName in ["PRE, PRE_ALL"]):
|
||||
return dramconfig.tRTP
|
||||
elif(SecondPhaseName in ["RD, RDA"]):
|
||||
return max(dramconfig.tCCD_L, getReadAccessTime())
|
||||
elif(SecondPhase in ["WR","WRA"]):
|
||||
return dramconfig.tRL + getReadAccessTime() - dramconfig.tWL + 2*dramconfig.clk
|
||||
elif(SecondPhase == "PDNA" ):
|
||||
return dramconfig.tRL + getReadAccessTime() + dramconfig.clk
|
||||
|
||||
elif(FirstPhaseName == "WR"):
|
||||
if(SecondPhaseName in ["PRE, PRE_ALL", "PDNA"]):
|
||||
return dramconfig.tWL + dramconfig.getWriteAccessTime() + dramconfig.tWR
|
||||
elif(SecondPhaseName in ["RD, RDA"]):
|
||||
return dramconfig.tWL + dramconfig.getWriteAccessTime() + dramconfig.tWTR_L
|
||||
elif(SecondPhaseName in ["WR, WRA"]):
|
||||
return max(dramconfig.tCCD_L, burstlength/dramconfig.dataRate)
|
||||
|
||||
elif(FirstPhaseName == "RDA"):
|
||||
if(SecondPhaseName in ["ACT", "PRE_ALL", "AUTO_REFRESH"]):
|
||||
return dramconfig.tRTP + dramconfig.tRP
|
||||
elif(SecondPhaseName in ["PDNA","PDNP"]):
|
||||
return dramconfig.tRL + getReadAccessTime() + dramconfig.clk
|
||||
|
||||
elif(FirstPhaseName == "WRA"):
|
||||
if(SecondPhaseName in ["ACT", "PRE_ALL", "AUTO_REFRESH"]):
|
||||
return dramconfig.tWL + getWriteAccessTime() + dramconfig.tWR + dramconfig.tRP
|
||||
elif(SecondPhaseName in ["PDNA","PDNP"]):
|
||||
return dramconfig.tWL + dramconfig.getWriteAccessTime() + dramconfig.tWR + dramconfig.clk
|
||||
|
||||
elif(FirstPhaseName == "AUTO_REFRESH"):
|
||||
return dramconfig.tRFC
|
||||
|
||||
elif(FirstPhaseName in ["PDNA","PDNP"]):
|
||||
return (FirstPhase[3] - FirstPhase[2]) + dramconfig.tXP - dramconfig.clk
|
||||
|
||||
elif(FirstPhaseName == "SREF"):
|
||||
return (FirstPhase[3] - FirstPhase[2]) + dramconfig.tXSR - dramconfig.clk
|
||||
|
||||
return 0
|
||||
|
||||
@test
|
||||
def timing_constraits_on_the_same_bank_hold(connection):
|
||||
"""Checks that all transitions of two consequtive phases on the same bank meet their timing constraints"""
|
||||
cursor = connection.cursor()
|
||||
validTransitions = {}
|
||||
|
||||
query = """SELECT PhaseName, phases.ID,PhaseBegin,PhaseEnd FROM phases INNER JOIN transactions ON phases.transact=transactions.ID WHERE TBank=:bank
|
||||
AND PhaseName NOT IN ('REQ','RESP') ORDER BY PhaseBegin"""
|
||||
|
||||
for bankNumber in range(dramconfig.numberOfBanks):
|
||||
cursor.execute(query, {"bank": bankNumber})
|
||||
lastRow = cursor.fetchone()
|
||||
|
||||
for currentRow in cursor:
|
||||
constraint = timing_constraint(lastRow,currentRow)
|
||||
if(currentRow[2] - lastRow[2] + constraint < 0):
|
||||
return TestFailed("Phase {0}({1}) starts {2} after Start of Phase {3}({4}). Minimal time is {5}".format(
|
||||
currentRow[1],currentRow[0],formatTime(currentRow[2]-lastRow[2]),lastRow[1],lastRow[0], formatTime(constraint)))
|
||||
lastRow = currentRow
|
||||
return TestSuceeded()
|
||||
|
||||
@test
|
||||
def row_buffer_is_used_correctly(connection):
|
||||
"""Checks that each bank's row buffer is used correctly"""
|
||||
|
||||
cursor = connection.cursor()
|
||||
query = """SELECT PhaseName, phases.ID FROM phases INNER JOIN transactions ON phases.transact=transactions.ID WHERE TBank=:bank
|
||||
AND PhaseName NOT IN ('REQ','RESP') ORDER BY PhaseBegin"""
|
||||
|
||||
|
||||
#phases that precharge the bank and close the rowbuffer
|
||||
prechargingPhases = set(['PRE','PRE_ALL','RDA','WRA'])
|
||||
|
||||
#phases that require the bank to be in active state and the rowbuffer to be opened
|
||||
accessingPhases = set(['RD','RDA', 'WR', 'WRA', 'PRE'])
|
||||
|
||||
#phases that require the bank to be in precharged state and the robuffer to be closed
|
||||
idlePhases = set(['ACT', 'PDNP', 'AUTO_REFRESH', 'SREF'])
|
||||
|
||||
for bankNumber in range(dramconfig.numberOfBanks):
|
||||
cursor.execute(query,{"bank": bankNumber})
|
||||
|
||||
rowBufferIsClosed = True
|
||||
|
||||
|
||||
|
||||
for currentRow in cursor:
|
||||
if(currentRow[0] in accessingPhases and rowBufferIsClosed == True):
|
||||
return TestFailed("Phase {0}({1}) acesses a closed rowbuffer".format(currentRow[1], currentRow[0]))
|
||||
|
||||
if(currentRow[0] in idlePhases and rowBufferIsClosed == False):
|
||||
return TestFailed("Phase {0}({1}) needs a closed rowbuffer".format(currentRow[1], currentRow[0]))
|
||||
|
||||
if(currentRow[0] == 'ACT'):
|
||||
rowBufferIsClosed = False
|
||||
|
||||
if(currentRow[0] in prechargingPhases):
|
||||
rowBufferIsClosed = True
|
||||
|
||||
return TestSuceeded()
|
||||
|
||||
#----------- activate checks ---------------------------------------
|
||||
@test
|
||||
def activate_to_activate_holds(connection):
|
||||
"""Checks that all activates are far enough apart(JESD229 229, P. 27)"""
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("SELECT phases.ID,PhaseBegin,TBankGroup FROM Phases INNER JOIN transactions ON phases.transact=transactions.ID WHERE PhaseName = 'ACT' ORDER BY PhaseBegin")
|
||||
lastRow = cursor.fetchone()
|
||||
|
||||
for currentRow in cursor:
|
||||
timeBetweenActivates = currentRow[1] - lastRow[1]
|
||||
if (currentRow[2] == lastRow[2]):
|
||||
minTime = dramconfig.tRRD_L
|
||||
else:
|
||||
minTime = dramconfig.tRRD_S
|
||||
if(timeBetweenActivates < minTime):
|
||||
return TestFailed("Activates with PhaseIDs {0} and {1} are {2} apart. Minimum time between two activates is {3}".
|
||||
format(currentRow[0], lastRow[0],formatTime(timeBetweenActivates), formatTime(minTime)))
|
||||
|
||||
lastRow = currentRow
|
||||
|
||||
return TestSuceeded()
|
||||
|
||||
|
||||
@test
|
||||
def activate_to_activate_on_same_bank_holds(connection):
|
||||
"""Checks that all activates on the same bank are far enough apart (JEDEC 229, P. 27)"""
|
||||
cursor = connection.cursor()
|
||||
query = "SELECT Phases.ID,PhaseBegin from Phases INNER JOIN Transactions ON Phases.Transact = Transactions.ID WHERE PhaseName = 'ACT' AND TBANK = :bank ORDER BY PhaseBegin"
|
||||
|
||||
for bankNumber in range(dramconfig.numberOfBanks):
|
||||
cursor.execute(query,{"bank": bankNumber})
|
||||
lastRow = cursor.fetchone()
|
||||
|
||||
for currentRow in cursor:
|
||||
timeBetweenActivates = currentRow[1] - lastRow[1];
|
||||
if(timeBetweenActivates < dramconfig.tRC):
|
||||
return TestFailed("Activates with PhaseIDs {0} and {1} are {2} apart. Minimum time between two activates is {3}, since they are on the same bank({4})".
|
||||
format(currentRow[0], lastRow[0],formatTime(timeBetweenActivates), dramconfig.tRC))
|
||||
else:
|
||||
lastRow = currentRow
|
||||
|
||||
return TestSuceeded()
|
||||
|
||||
@test
|
||||
def n_activate_window_holds(connection):
|
||||
"""Checks that the n-Activate constraint is met everywhere(JEDEC 229, P. 27)"""
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("SELECT ID,PhaseBegin from Phases WHERE PhaseName = 'ACT' ORDER BY PhaseBegin")
|
||||
activateWindow = []
|
||||
|
||||
for currentRow in cursor:
|
||||
activateWindow.append(currentRow[1])
|
||||
if(len(activateWindow) > dramconfig.nActivateWindow + 1):
|
||||
activateWindow.pop(0)
|
||||
if(activateWindow[dramconfig.nActivateWindow] - activateWindow[0] < dramconfig.tNAW):
|
||||
return TestFailed("Activate with PhaseID {0} and the {1} preceeding activates violate the '{1} activate window' constraint."
|
||||
" No more than {1} activates should be in rolling time window of {2}".format(currentRow[0], dramconfig.nActivateWindow,formatTime(dramconfig.tNAW)))
|
||||
return TestSuceeded()
|
||||
|
||||
|
||||
# ----------- read/write checks ---------------------------------------
|
||||
@test
|
||||
def read_to_read_holds(connection):
|
||||
"""Check that the read operations do not intefere with each other on the data bus"""
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("SELECT phases.ID,PhaseBegin,TBankGroup FROM Phases INNER JOIN transactions ON phases.transact=transactions.ID WHERE PhaseName IN ('RD','RDA') ORDER BY PhaseBegin")
|
||||
lastRow = cursor.fetchone()
|
||||
|
||||
for currentRow in cursor:
|
||||
timeBetweenReads = currentRow[1] - lastRow[1]
|
||||
if (currentRow[2] == lastRow[2]):
|
||||
minTime = max(dramconfig.tCCD_L,dramconfig.getReadAccessTime())
|
||||
else:
|
||||
minTime = max(dramconfig.tCCD_S,dramconfig.getReadAccessTime())
|
||||
if(timeBetweenReads < minTime):
|
||||
return TestFailed("Reads with PhaseIDs {0} and {1} are {2} apart. Minimum time between two reads is {3}".format(currentRow[0], lastRow[0],formatTime(timeBetweenReads), minTime))
|
||||
lastRow = currentRow
|
||||
|
||||
return TestSuceeded()
|
||||
|
||||
|
||||
@test
|
||||
def write_to_write_holds(connection):
|
||||
"""Check that the write operations do not intefere with each other on the data bus"""
|
||||
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("SELECT phases.ID,PhaseBegin,TBankGroup FROM Phases INNER JOIN transactions ON phases.transact=transactions.ID WHERE PhaseName IN ('WR','WRA') ORDER BY PhaseBegin")
|
||||
lastRow = cursor.fetchone()
|
||||
|
||||
for currentRow in cursor:
|
||||
timeBetweenWrites = currentRow[1] - lastRow[1]
|
||||
if (currentRow[2] == lastRow[2]):
|
||||
minTime = max(dramconfig.tCCD_L,dramconfig.getWriteAccessTime())
|
||||
else:
|
||||
minTime = max(dramconfig.tCCD_S,dramconfig.getWriteAccessTime())
|
||||
if(timeBetweenWrites < minTime):
|
||||
return TestFailed("Writes with PhaseIDs {0} and {1} are {2} apart. Minimum time between two writes is {3}".format(currentRow[0], lastRow[0],formatTime(timeBetweenWrites), minTime))
|
||||
lastRow = currentRow
|
||||
return TestSuceeded()
|
||||
|
||||
@test
|
||||
def write_to_read_and_read_to_write_hold(connection):
|
||||
"""Checks that read and write operation do not interfere with each other on the data bus
|
||||
and that the write-to-read constraint is met"""
|
||||
|
||||
cursor = connection.cursor()
|
||||
query = """SELECT Phases.ID,PhaseBegin,PhaseName,TBankGroup from Phases INNER JOIN Transactions ON Phases.Transact = Transactions.ID
|
||||
WHERE PhaseName IN ('RD','WR','RDA','WRA') ORDER BY PhaseBegin"""
|
||||
|
||||
cursor.execute(query)
|
||||
lastRow = cursor.fetchone()
|
||||
|
||||
for currentRow in cursor:
|
||||
|
||||
if(currentRow[2] in ["RD","RDA"] and lastRow[2] in ["WR","WRA"]):
|
||||
#write to read
|
||||
if (currentRow[3] == lastRow[3]):
|
||||
tWTR = dramconfig.tWTR_L
|
||||
else:
|
||||
tWTR = dramconfig.tWTR_S
|
||||
|
||||
minWriteToRead = dramconfig.tWL + dramconfig.getWriteAccessTime() + tWTR
|
||||
writeToRead = currentRow[1] - lastRow[1]
|
||||
|
||||
if(writeToRead < minWriteToRead ):
|
||||
return TestFailed("Read {0} starts {1} after start of write {2}. Minimum time is {3}".
|
||||
format(currentRow[0],formatTime(writeToRead),lastRow[0], formatTime(minWriteToRead)))
|
||||
|
||||
elif(currentRow[2] in ["WR","WRA"] and lastRow[2] in ["RD","RDA"]):
|
||||
#read to write
|
||||
minReadToWrite = dramconfig.tRL + dramconfig.getReadAccessTime() - dramconfig.tWL + dramconfig.clk * 2
|
||||
readToWrite = currentRow[1] - lastRow[1]
|
||||
if(readToWrite < minReadToWrite ):
|
||||
return TestFailed("Write {0} starts {1} after start of read {2}. Minimum time is {3}".
|
||||
format(currentRow[0],formatTime(readToWrite),lastRow[0], formatTime(minWriteToRead)))
|
||||
|
||||
lastRow = currentRow
|
||||
|
||||
return TestSuceeded()
|
||||
|
||||
|
||||
@test
|
||||
def read_holds_dll_constraint_after_sref(connection):
|
||||
"""Checks that all read operations are delayed long enough after the end of the self refresh powerdown state"""
|
||||
|
||||
cursor = connection.cursor()
|
||||
query = """SELECT Phases.ID,PhaseBegin,PhaseName,TBankGroup from Phases INNER JOIN Transactions ON Phases.Transact = Transactions.ID AND TBank = :bank
|
||||
WHERE PhaseName IN ('RD', 'RDA', 'SREF') ORDER BY PhaseBegin"""
|
||||
|
||||
|
||||
for bankNumber in range(dramconfig.numberOfBanks):
|
||||
cursor.execute(query,{"bank": bankNumber})
|
||||
lastRow = cursor.fetchone()
|
||||
for currentRow in cursor:
|
||||
if(currentRow[2] in ["RD","RDA"] and lastRow[2] == 'SREF'):
|
||||
srefEndToRead = currentRow[1] - (lastRow[1] - dramconfig.clk)
|
||||
if(srefEndToRead < dramconfig.tXSRDLL ):
|
||||
return TestFailed("Read {0} starts {1} after end of sref {2}. Minimum time is {3}".
|
||||
format(currentRow[0],formatTime(srefEndToRead),lastRow[0], formatTime(dramconfig.tXSRDLL)))
|
||||
lastRow = currentRow
|
||||
return TestSuceeded()
|
||||
|
||||
# ----------- powerdown checks ---------------------------------------
|
||||
|
||||
# @test
|
||||
# def sref_active_for_minimal_time(connection):
|
||||
# """Checks that after entering self refresh powerndown state, the state is active for a minimal time (JEDEC 229, P. 41)"""
|
||||
#
|
||||
# cursor = connection.cursor()
|
||||
# cursor.execute("SELECT ID, PhaseEnd-clk-PhaseBegin FROM Phases, GeneralInfo WHERE PhaseName = 'SREF'")
|
||||
# for currentRow in cursor:
|
||||
# if(currentRow[1] < dramconfig.tCKESR):
|
||||
# return TestFailed("SREF with ID {0} is {1} long. Minimal time in SREF is {2}".format(currentRow[0], formatTime(currentRow[1]), dramconfig.tCKESR))
|
||||
# return TestSuceeded()
|
||||
|
||||
# @test
|
||||
# def pdna_pdnp_active_for_minimal_time(connection):
|
||||
# """Checks that after entering active/precharged powerdown, the state is active for a minimal time (JEDEC 229, P. 41)"""
|
||||
#
|
||||
# cursor = connection.cursor()
|
||||
# cursor.execute("SELECT ID,PhaseName, PhaseEnd-PhaseBegin FROM Phases, GeneralInfo WHERE PhaseName IN ('PDNA', 'PDNP') ")
|
||||
# for currentRow in cursor:
|
||||
# if(currentRow[2] < dramconfig.tCKE):
|
||||
# return TestFailed("{0} with ID {1} is {2} long. Minimal time in SREF is {3}".format(currentRow[1], currentRow[0], formatTime(currentRow[2]), dramconfig.tCKE))
|
||||
# return TestSuceeded()
|
||||
|
||||
# -------------------------- interface methods --------------------
|
||||
|
||||
def runTests(pathToTrace):
|
||||
print(pathToTrace)
|
||||
connection = sqlite3.connect(pathToTrace)
|
||||
dramconfig.readConfigFromFiles(connection)
|
||||
|
||||
testResults = []
|
||||
numberOfFailedTest = 0
|
||||
print("================================")
|
||||
print("RUNNING TEST ON {0}".format(pathToTrace))
|
||||
|
||||
print("-----------------------------\n")
|
||||
|
||||
for test in tests:
|
||||
testResult = test(connection)
|
||||
testName = test.__name__.replace("_"," ")
|
||||
testResults.append((testName, testResult.passed,testResult.message))
|
||||
|
||||
if(testResult.passed):
|
||||
print("[passed] {0}".format(testName))
|
||||
else:
|
||||
print("[failed] {0} failed. Message: {1}".format(testName, testResult.message))
|
||||
numberOfFailedTest = numberOfFailedTest + 1
|
||||
|
||||
print("\n-----------------------------")
|
||||
|
||||
if(numberOfFailedTest == 0):
|
||||
print("All tests passed")
|
||||
else:
|
||||
print("{0} of {1} tests passed".format(len(tests) - numberOfFailedTest,len(tests)))
|
||||
|
||||
print("================================")
|
||||
connection.close()
|
||||
|
||||
return testResults
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w')
|
||||
for i in range(1,len(sys.argv)):
|
||||
runTests(sys.argv[i])
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
<simulation id="datasizes">
|
||||
<memspec>JEDEC_256Mb_WIDEIO_SDR-266_128bit.xml</memspec>
|
||||
<addressmapping>am_wideioFourBanks.xml</addressmapping>
|
||||
<memconfigs>
|
||||
<memconfig>fr_fcfs_unaware.xml</memconfig>
|
||||
</memconfigs>
|
||||
<trace-setups>
|
||||
|
||||
<trace-setup id="1">
|
||||
<device >chstone-aes_32.stl</device>
|
||||
<device >chstone-motion_32.stl</device>
|
||||
</trace-setup>
|
||||
|
||||
<trace-setup id="2">
|
||||
<device >chstone-motion_32.stl</device>
|
||||
<device >chstone-jpeg_32.stl</device>
|
||||
</trace-setup>
|
||||
|
||||
|
||||
|
||||
</trace-setups>
|
||||
</simulation>
|
||||
@@ -1,25 +1,25 @@
|
||||
<simulation>
|
||||
<simconfig>
|
||||
<Debug value="1" />
|
||||
<Debug value="1" />
|
||||
<DatabaseRecording value="1" />
|
||||
<PowerAnalysys value="0" />
|
||||
</simconfig>
|
||||
<memspecs>
|
||||
<memspec src="/home/jonny/newconfigs/mems.xml"></memspec>
|
||||
<memspec src="/home/gernhard2/projects/dram.vp.system/dram/resources/configs/memspecs/WideIO.xml"></memspec>
|
||||
</memspecs>
|
||||
<addressmappings>
|
||||
<addressmapping src="/home/jonny/newconfigs/amc.xml"></addressmapping>
|
||||
<addressmapping src="/home/gernhard2/projects/dram.vp.system/dram/resources/configs/amconfigs/am_wideio.xml"></addressmapping>
|
||||
</addressmappings>
|
||||
<memconfigs>
|
||||
<memconfig src="/home/jonny/newconfigs/memc.xml">
|
||||
</memconfig>
|
||||
<memconfig src="/home/gernhard2/projects/dram.vp.system/dram/resources/configs/memconfigs/fifo.xml"/>
|
||||
|
||||
</memconfigs>
|
||||
|
||||
<tracesetups>
|
||||
|
||||
<tracesetup id="medium">
|
||||
<!--<device clkMhz="200">test.stl</device>-->
|
||||
<device clkMhz="200">small.stl</device>
|
||||
<tracesetups>
|
||||
<tracesetup id="fifo">
|
||||
<!--<device clkMhz="200">test.stl</device>-->
|
||||
<device clkMhz="200">mediabench-epic_32.stl</device>
|
||||
</tracesetup>
|
||||
|
||||
</tracesetups>
|
||||
</simulation>
|
||||
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
*/
|
||||
|
||||
#include "DebugManager.h"
|
||||
#include "../controller/core/configuration/Configuration.h"
|
||||
using namespace std;
|
||||
|
||||
void DebugManager::printDebugMessage(string sender, string message)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (whiteList.count(sender))
|
||||
if(Configuration::getInstance().Debug)
|
||||
{
|
||||
if (writeToConsole)
|
||||
cout << " at " << sc_time_stamp() << "\t in " << sender << "\t: " << message << endl;
|
||||
@@ -19,7 +19,6 @@ void DebugManager::printDebugMessage(string sender, string message)
|
||||
if (writeToFile && debugFile)
|
||||
debugFile << " at " << sc_time_stamp() << " in " << sender << "\t: " << message << "\n";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void DebugManager::openDebugFile(string filename)
|
||||
@@ -29,17 +28,6 @@ void DebugManager::openDebugFile(string filename)
|
||||
debugFile.open(filename);
|
||||
}
|
||||
|
||||
void DebugManager::addToWhiteList(string sender)
|
||||
{
|
||||
whiteList.insert(sender);
|
||||
}
|
||||
|
||||
void DebugManager::addToWhiteList(vector<string> senders)
|
||||
{
|
||||
for (string sender : senders)
|
||||
addToWhiteList(sender);
|
||||
}
|
||||
|
||||
DebugManager::DebugManager() :
|
||||
writeToConsole(true), writeToFile(true)
|
||||
{
|
||||
|
||||
@@ -28,15 +28,11 @@ public:
|
||||
void printDebugMessage(std::string sender, std::string message);
|
||||
void openDebugFile(std::string filename);
|
||||
|
||||
void addToWhiteList(std::string sender);
|
||||
void addToWhiteList(std::vector<std::string> senders);
|
||||
|
||||
private:
|
||||
DebugManager();
|
||||
DebugManager(const DebugManager&){}
|
||||
|
||||
ofstream debugFile;
|
||||
std::set<std::string> whiteList;
|
||||
};
|
||||
|
||||
#endif /* DEBUGMANAGER_H_ */
|
||||
|
||||
@@ -158,12 +158,17 @@ void TlmRecorder::Transaction::insertPhase(string name, sc_time begin)
|
||||
|
||||
void TlmRecorder::Transaction::setPhaseEnd(string name, sc_time end)
|
||||
{
|
||||
for(Phase& data: recordedPhases)
|
||||
// Find the latest recorder phase for that transaction with a matching name and update it
|
||||
// Note: Transaction have the same phase multiple times (e.g. PRE->ACT->REF->ACT->RD) only update the latest
|
||||
// one that has been recorder
|
||||
for(int i = recordedPhases.size() - 1; i >= 0;i--)
|
||||
{
|
||||
Phase& data = recordedPhases[i];
|
||||
if(data.name == name)
|
||||
{
|
||||
data.interval.end = end;
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
SC_REPORT_FATAL("Recording Error", "While trying to set phase end: phaseBegin has not been recorded");
|
||||
@@ -240,8 +245,8 @@ void TlmRecorder::insertGeneralInfo()
|
||||
sqlite3_bind_int64(insertGeneralInfoStatement, 1, totalNumTransactions - 1);
|
||||
sqlite3_bind_int64(insertGeneralInfoStatement, 2, simulationTimeCoveredByRecording.value());
|
||||
sqlite3_bind_int(insertGeneralInfoStatement, 3,
|
||||
core::Configuration::getInstance().memSpec.NumberOfBanks);
|
||||
sqlite3_bind_int(insertGeneralInfoStatement, 4, core::Configuration::getInstance().memSpec.clk.value());
|
||||
Configuration::getInstance().memSpec.NumberOfBanks);
|
||||
sqlite3_bind_int(insertGeneralInfoStatement, 4, Configuration::getInstance().memSpec.clk.value());
|
||||
sqlite3_bind_text(insertGeneralInfoStatement, 5, "PS", 2, NULL);
|
||||
sqlite3_bind_text(insertGeneralInfoStatement, 6, memconfig.c_str(), memconfig.length(), NULL);
|
||||
sqlite3_bind_text(insertGeneralInfoStatement, 7, memspec.c_str(), memspec.length(), NULL);
|
||||
|
||||
@@ -35,6 +35,26 @@ DramExtension& DramExtension::getExtension(const tlm_generic_payload &payload)
|
||||
return DramExtension::getExtension(&payload);
|
||||
}
|
||||
|
||||
Bank DramExtension::getBank(const tlm_generic_payload *payload)
|
||||
{
|
||||
return DramExtension::getExtension(payload).getBank();
|
||||
}
|
||||
|
||||
Bank DramExtension::getBank(const tlm_generic_payload &payload)
|
||||
{
|
||||
return DramExtension::getBank(&payload);
|
||||
}
|
||||
|
||||
Row DramExtension::getRow(const tlm_generic_payload *payload)
|
||||
{
|
||||
return DramExtension::getExtension(payload).getRow();
|
||||
}
|
||||
|
||||
Row DramExtension::getRow(const tlm_generic_payload &payload)
|
||||
{
|
||||
return DramExtension::getRow(&payload);
|
||||
}
|
||||
|
||||
|
||||
tlm_extension_base* DramExtension::clone() const
|
||||
{
|
||||
@@ -184,7 +204,7 @@ bool operator !=(const Row& lhs, const Row& rhs)
|
||||
|
||||
const Row Row::operator ++()
|
||||
{
|
||||
id = (id + 1) % core::Configuration::getInstance().memSpec.NumberOfRows;
|
||||
id = (id + 1) % Configuration::getInstance().memSpec.NumberOfRows;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
@@ -76,6 +76,12 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string toString()
|
||||
{
|
||||
return std::to_string(id);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
unsigned int id;
|
||||
};
|
||||
@@ -135,9 +141,16 @@ public:
|
||||
|
||||
virtual tlm_extension_base* clone() const;
|
||||
virtual void copy_from(const tlm_extension_base& ext);
|
||||
|
||||
static DramExtension& getExtension(const tlm::tlm_generic_payload *payload);
|
||||
static DramExtension& getExtension(const tlm::tlm_generic_payload &payload);
|
||||
|
||||
// Used for convience, caller could also use getExtension(..) to access these field
|
||||
static Bank getBank(const tlm::tlm_generic_payload *payload);
|
||||
static Bank getBank(const tlm::tlm_generic_payload &payload);
|
||||
static Row getRow(const tlm::tlm_generic_payload *payload);
|
||||
static Row getRow(const tlm::tlm_generic_payload &payload);
|
||||
|
||||
Thread getThread() const;
|
||||
Channel getChannel() const;
|
||||
Bank getBank() const;
|
||||
|
||||
2
dram/src/common/third_party/DRAMPower
vendored
2
dram/src/common/third_party/DRAMPower
vendored
Submodule dram/src/common/third_party/DRAMPower updated: 7723662db4...e39b6d6668
@@ -52,8 +52,8 @@ DecodedAddress xmlAddressDecoder::decodeAddress(sc_dt::uint64 addr)
|
||||
//result.rank = (addr & masks["rank"]) >> shifts["rank"];
|
||||
//result.bankgroup = (addr & masks["bankgroup"]) >> shifts["bankgroup"];
|
||||
result.bank = (addr & masks["bank"]) >> shifts["bank"];
|
||||
result.bankgroup = result.bank % core::Configuration::getInstance().memSpec.NumberOfBankGroups;
|
||||
result.rank = result.bank % core::Configuration::getInstance().memSpec.NumberOfRanks;
|
||||
result.bankgroup = result.bank % Configuration::getInstance().memSpec.NumberOfBankGroups;
|
||||
result.rank = result.bank % Configuration::getInstance().memSpec.NumberOfRanks;
|
||||
result.row = (addr & masks["row"]) >> shifts["row"];
|
||||
result.column = (addr & masks["column"]) >> shifts["column"];
|
||||
result.bytes = (addr & masks["bytes"]) >> shifts["bytes"];
|
||||
|
||||
78
dram/src/controller/Command.cpp
Normal file
78
dram/src/controller/Command.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
#include "Command.h"
|
||||
#include <systemc.h>
|
||||
|
||||
|
||||
std::string commandToString(Command command)
|
||||
{
|
||||
switch (command)
|
||||
{
|
||||
case Command::Read:
|
||||
return "RD";
|
||||
break;
|
||||
case Command::ReadA:
|
||||
return "RDA";
|
||||
break;
|
||||
case Command::Write:
|
||||
return "WR";
|
||||
break;
|
||||
case Command::WriteA:
|
||||
return "WRA";
|
||||
break;
|
||||
case Command::Precharge:
|
||||
return "PRE";
|
||||
break;
|
||||
case Command::Activate:
|
||||
return "ACT";
|
||||
break;
|
||||
case Command::PrechargeAll:
|
||||
return "PRE_ALL";
|
||||
break;
|
||||
case Command::AutoRefresh:
|
||||
return "AUTO_REFRESH";
|
||||
break;
|
||||
|
||||
case Command::PDNA:
|
||||
return "PDNA";
|
||||
break;
|
||||
case Command::PDNAX:
|
||||
return "PDNAX";
|
||||
break;
|
||||
case Command::PDNP:
|
||||
return "PDNP";
|
||||
break;
|
||||
case Command::PDNPX:
|
||||
return "PDNPX";
|
||||
break;
|
||||
case Command::SREF:
|
||||
return "SREF";
|
||||
break;
|
||||
case Command::SREFX:
|
||||
return "SREFX";
|
||||
break;
|
||||
|
||||
default:
|
||||
SC_REPORT_FATAL("command", "commandToString was called with unknown command");
|
||||
break;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
const std::vector<Command>& getAllCommands()
|
||||
{
|
||||
static std::vector<Command> allCommands( { Command::Precharge, Command::PrechargeAll,
|
||||
Command::Activate, Command::Read, Command::Write, Command::ReadA, Command::WriteA,
|
||||
Command::AutoRefresh, Command::PDNA, Command::PDNAX, Command::PDNP, Command::PDNPX,
|
||||
Command::SREF, Command::SREFX });
|
||||
return allCommands;
|
||||
}
|
||||
|
||||
bool commandIsIn(Command command, std::vector<Command> commands)
|
||||
{
|
||||
for (Command c : commands)
|
||||
{
|
||||
if (c == command)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -10,16 +10,10 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace core {
|
||||
|
||||
enum class Command {NOP, Precharge, PrechargeAll, Activate, Read, Write, ReadA, WriteA, AutoRefresh, PDNA, PDNAX, PDNP, PDNPX, SREF, SREFX};
|
||||
std::string commandToString(Command command);
|
||||
|
||||
const std::vector<Command>& getAllCommands();
|
||||
|
||||
|
||||
typedef std::vector<Command> CommandSequence;
|
||||
|
||||
} /* namespace controller */
|
||||
bool commandIsIn(Command command, std::vector<Command> commands);
|
||||
|
||||
#endif /* COMMAND_H_ */
|
||||
@@ -25,26 +25,24 @@
|
||||
#include "../common/Utils.h"
|
||||
#include "core/configuration/Configuration.h"
|
||||
#include "core/configuration/MemSpec.h"
|
||||
#include "core/Command.h"
|
||||
#include "Command.h"
|
||||
#include "core/ControllerCore.h"
|
||||
#include "core/ControllerState.h"
|
||||
#include "core/IWrapperConnector.h"
|
||||
#include "ControllerState.h"
|
||||
#include "IController.h"
|
||||
#include "core/powerdown/IPowerDownManager.h"
|
||||
#include "core/scheduling/ScheduledCommand.h"
|
||||
#include "core/scheduling/Trigger.h"
|
||||
#include "core/TimingCalculation.h"
|
||||
#include "scheduler/Fifo.h"
|
||||
#include "scheduler/FifoStrict.h"
|
||||
#include "scheduler/Fr_Fcfs.h"
|
||||
#include "scheduler/PARBS.h"
|
||||
#include "scheduler/readwritegrouper.h"
|
||||
#include "scheduler/IScheduler.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace tlm;
|
||||
using namespace core;
|
||||
using namespace scheduler;
|
||||
|
||||
template<unsigned int BUSWIDTH = 128>
|
||||
struct Controller: public sc_module, public IWrapperConnector
|
||||
struct Controller: public sc_module, public IController
|
||||
{
|
||||
public:
|
||||
Controller(sc_module_name /*name*/) :
|
||||
@@ -59,7 +57,7 @@ public:
|
||||
|
||||
~Controller()
|
||||
{
|
||||
delete controllerCore;
|
||||
delete controllerCore;
|
||||
delete scheduler;
|
||||
}
|
||||
|
||||
@@ -69,7 +67,6 @@ public:
|
||||
virtual void send(const ScheduledCommand& command, tlm_generic_payload& payload) override;
|
||||
virtual void send(Trigger trigger, sc_time time, tlm_generic_payload& payload) override;
|
||||
|
||||
|
||||
tlm_utils::simple_initiator_socket<Controller, BUSWIDTH, tlm::tlm_base_protocol_types> iSocket;
|
||||
tlm_utils::simple_target_socket<Controller, BUSWIDTH, tlm::tlm_base_protocol_types> tSocket;
|
||||
|
||||
@@ -78,10 +75,7 @@ private:
|
||||
void payloadEntersSystem(tlm_generic_payload& payload);
|
||||
void payloadLeavesSystem(tlm_generic_payload& payload);
|
||||
unsigned int getTotalNumberOfPayloadsInSystem();
|
||||
void scheduleNextFromScheduler();
|
||||
//FIFO HACK
|
||||
void scheduleDirectly(gp* payload);
|
||||
|
||||
void scheduleNextFromScheduler(Bank bank);
|
||||
|
||||
// --- FRONTEND ------
|
||||
tlm_sync_enum nb_transport_fw(tlm_generic_payload& payload, tlm_phase& phase, sc_time& fwDelay);
|
||||
@@ -96,12 +90,13 @@ private:
|
||||
// ------- CONTROLLER CORE ---------
|
||||
void controllerCorePEQCallback(tlm_generic_payload& payload, const tlm_phase& phase);
|
||||
|
||||
//Helpers TODO move them
|
||||
// Helpers TODO move them
|
||||
void printDebugMessage(string message);
|
||||
bool containsPhase(tlm_phase phase, std::vector<tlm_phase> phases);
|
||||
|
||||
ControllerCore* controllerCore;
|
||||
Scheduler* scheduler;
|
||||
//Scheduler* scheduler;
|
||||
IScheduler* scheduler;
|
||||
std::map<Bank, int> numberOfPayloadsInSystem;
|
||||
std::vector<gp* > refreshCollisionRequets;
|
||||
tlm::tlm_generic_payload* backpressure = NULL;
|
||||
@@ -123,23 +118,27 @@ void Controller<BUSWIDTH>::buildScheduler()
|
||||
{
|
||||
string selectedScheduler = Configuration::getInstance().Scheduler;
|
||||
|
||||
if (selectedScheduler == "FR_FCFS")
|
||||
if (selectedScheduler == "FIFO")
|
||||
{
|
||||
scheduler = new FR_FCFS(*controllerCore, Configuration::getInstance().RefreshAwareScheduling,Configuration::getInstance().AdaptiveOpenPagePolicy);
|
||||
scheduler = new Fifo(*controllerCore);
|
||||
}
|
||||
else if (selectedScheduler == "PAR_BS")
|
||||
else if (selectedScheduler == "FIFO_STRICT")
|
||||
{
|
||||
scheduler = new PAR_BS(*controllerCore, Configuration::getInstance().RefreshAwareScheduling,
|
||||
Configuration::getInstance().Capsize);
|
||||
scheduler = new FifoStrict(*this, *controllerCore);
|
||||
}
|
||||
else if (selectedScheduler == "FIFO")
|
||||
else if (selectedScheduler == "FR_FCFS")
|
||||
{
|
||||
scheduler = new Fifo(*controllerCore);
|
||||
}
|
||||
else if (selectedScheduler == "Grouper")
|
||||
{
|
||||
scheduler = new ReadWriteGrouper(*controllerCore);
|
||||
scheduler = new FR_FCFS(*controllerCore);
|
||||
}
|
||||
// else if (selectedScheduler == "PAR_BS")
|
||||
// {
|
||||
// scheduler = new PAR_BS(*controllerCore, Configuration::getInstance().RefreshAwareScheduling,
|
||||
// Configuration::getInstance().Capsize);
|
||||
// }
|
||||
// else if (selectedScheduler == "Grouper")
|
||||
// {
|
||||
// scheduler = new ReadWriteGrouper(*controllerCore);
|
||||
// }
|
||||
else
|
||||
reportFatal(name(), "unsupported scheduler: " + selectedScheduler);
|
||||
}
|
||||
@@ -152,6 +151,7 @@ void Controller<BUSWIDTH>::send(const ScheduledCommand &command, tlm_generic_pay
|
||||
|
||||
switch (command.getCommand())
|
||||
{
|
||||
//TODO: refactor tlm recorder
|
||||
case Command::Read:
|
||||
dataStrobe = command.getIntervalOnDataStrobe();
|
||||
TlmRecorder::getInstance().updateDataStrobe(dataStrobe.start, dataStrobe.end, payload);
|
||||
@@ -284,11 +284,22 @@ void Controller<BUSWIDTH>::controllerCorePEQCallback(tlm_generic_payload &payloa
|
||||
}
|
||||
else
|
||||
{
|
||||
Bank bank = DramExtension::getExtension(payload).getBank();
|
||||
Bank bank = DramExtension::getBank(payload);
|
||||
sendToDram(payload, phase, SC_ZERO_TIME);
|
||||
|
||||
if (phase == BEGIN_RD || phase == BEGIN_WR)
|
||||
scheduleNextFromScheduler();
|
||||
{
|
||||
if(Configuration::getInstance().Scheduler == "FIFO_STRICT")
|
||||
{
|
||||
// special case for the Fifo_strict scheduler, because it may have to unblock
|
||||
// the current front element
|
||||
dynamic_cast<FifoStrict*>(scheduler)->NotifyBeginRD();
|
||||
}
|
||||
else
|
||||
{
|
||||
scheduleNextFromScheduler(DramExtension::getBank(payload));
|
||||
}
|
||||
}
|
||||
else if (phase == BEGIN_REFB)
|
||||
printDebugMessage("Entering REFB on bank " + to_string(bank.ID()));
|
||||
else if (phase == BEGIN_REFA)
|
||||
@@ -343,17 +354,13 @@ void Controller<BUSWIDTH>::frontendPEQCallback(tlm_generic_payload &payload, con
|
||||
payload.set_response_status(tlm::TLM_OK_RESPONSE);
|
||||
sendToFrontend(payload, END_REQ, SC_ZERO_TIME);
|
||||
|
||||
//FIFO HACK
|
||||
if(Configuration::getInstance().Scheduler == "FIFO")
|
||||
{
|
||||
scheduleDirectly(&payload);
|
||||
}
|
||||
//Original
|
||||
else
|
||||
{
|
||||
scheduler->schedule(&payload);
|
||||
scheduleNextFromScheduler();
|
||||
}
|
||||
scheduler->schedule(&payload);
|
||||
|
||||
// Since we are triggering the scheduling of the next action on the bank
|
||||
// because of an incoming transaction, we have to check if the bank
|
||||
// is still busy. If it is, we let the end of the command which is currently in
|
||||
// progress trigger the next scheduling
|
||||
scheduleNextFromScheduler(DramExtension::getExtension(payload).getBank());
|
||||
}
|
||||
else if (phase == END_RESP)
|
||||
{
|
||||
@@ -363,15 +370,14 @@ void Controller<BUSWIDTH>::frontendPEQCallback(tlm_generic_payload &payload, con
|
||||
backpressure->set_response_status(tlm::TLM_OK_RESPONSE);
|
||||
sendToFrontend(*backpressure, END_REQ, SC_ZERO_TIME);
|
||||
|
||||
//FIFO HACK
|
||||
if(Configuration::getInstance().Scheduler == "FIFO")
|
||||
scheduler->schedule(backpressure);
|
||||
// Since we are triggering the scheduling of the next action on the bank
|
||||
// because of an incoming transaction, we have to check if the bank
|
||||
// is still busy. If it is, we let the end of the command which is currently in
|
||||
// progress trigger the next scheduling
|
||||
if(!controllerCore->bankIsBusy(DramExtension::getBank(payload)))
|
||||
{
|
||||
scheduleDirectly(backpressure);
|
||||
}
|
||||
else
|
||||
{
|
||||
scheduler->schedule(backpressure);
|
||||
scheduleNextFromScheduler();
|
||||
scheduleNextFromScheduler(DramExtension::getExtension(backpressure).getBank());
|
||||
}
|
||||
backpressure = NULL;
|
||||
}
|
||||
@@ -417,33 +423,19 @@ unsigned int Controller<BUSWIDTH>::getTotalNumberOfPayloadsInSystem()
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
||||
//FIFO HACK!
|
||||
template<unsigned int BUSWIDTH>
|
||||
void Controller<BUSWIDTH>::scheduleDirectly(gp* payload)
|
||||
void Controller<BUSWIDTH>::scheduleNextFromScheduler(Bank bank)
|
||||
{
|
||||
if(!controllerCore->scheduleRequest(*payload))
|
||||
if(controllerCore->bankIsBusy(bank))
|
||||
{
|
||||
refreshCollisionRequets.push_back(payload);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
template<unsigned int BUSWIDTH>
|
||||
void Controller<BUSWIDTH>::scheduleNextFromScheduler()
|
||||
{
|
||||
if(scheduler->hasPayloads())
|
||||
pair<Command, tlm::tlm_generic_payload*> nextRequest = scheduler->getNextRequest(bank);
|
||||
if(nextRequest.second != NULL)
|
||||
{
|
||||
tlm_generic_payload* payload = scheduler->getNextPayload();
|
||||
if(payload != NULL)
|
||||
{
|
||||
controllerCore->powerDownManager->wakeUp(DramExtension::getExtension(payload).getBank(), sc_time_stamp());
|
||||
bool wasScheduledByCore = controllerCore->scheduleRequest(*payload);
|
||||
if (wasScheduledByCore)
|
||||
{
|
||||
scheduler->removePayload(payload);
|
||||
printDebugMessage("\t-> Next payload was scheduled by core");
|
||||
}
|
||||
}
|
||||
controllerCore->powerDownManager->wakeUp(DramExtension::getExtension(nextRequest.second).getBank(), sc_time_stamp());
|
||||
controllerCore->scheduleRequest(nextRequest.first, *nextRequest.second);
|
||||
printDebugMessage("\t-> Next payload was scheduled by core");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -469,44 +461,53 @@ void Controller<BUSWIDTH>::dramPEQCallback(tlm_generic_payload &payload, const t
|
||||
Bank bank = DramExtension::getExtension(payload).getBank();
|
||||
printDebugMessage("Received " + phaseNameToString(phase) + " on bank " + to_string(bank.ID()) + " from DRAM");
|
||||
|
||||
if (phase == BEGIN_RD || phase == BEGIN_WR)
|
||||
{
|
||||
scheduleNextFromScheduler();
|
||||
sendToDram(payload, phase, SC_ZERO_TIME);
|
||||
}
|
||||
else if (phase == END_RD || phase == END_WR)
|
||||
if (phase == END_RD || phase == END_WR)
|
||||
{
|
||||
sendToFrontend(payload, BEGIN_RESP, SC_ZERO_TIME);
|
||||
}
|
||||
else if (phase == END_RDA || phase == END_WRA)
|
||||
{
|
||||
sendToFrontend(payload, BEGIN_RESP, SC_ZERO_TIME);
|
||||
scheduleNextFromScheduler();
|
||||
scheduleNextFromScheduler(bank);
|
||||
}
|
||||
else if (phase == END_REFA || phase == END_REFB)
|
||||
else if (phase == END_REFA)
|
||||
{
|
||||
printDebugMessage("Finished auto refresh on bank " + to_string(bank.ID()));
|
||||
printDebugMessage("Finished auto refresh on all banks ");
|
||||
|
||||
if(numberOfPayloadsInSystem[bank] == 0)
|
||||
controllerCore->powerDownManager->sleep(bank,sc_time_stamp());
|
||||
//FIFO HACK
|
||||
if(Configuration::getInstance().Scheduler == "FIFO")
|
||||
for(Bank bank : controllerCore->getBanks())
|
||||
{
|
||||
std::vector<gp*> collidedReq = this->refreshCollisionRequets;
|
||||
refreshCollisionRequets.clear();
|
||||
for(gp* payload : collidedReq)
|
||||
if(numberOfPayloadsInSystem[bank] == 0)
|
||||
{
|
||||
scheduleDirectly(payload);
|
||||
controllerCore->powerDownManager->sleep(bank,sc_time_stamp());
|
||||
}
|
||||
else
|
||||
{
|
||||
scheduleNextFromScheduler(bank);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
scheduleNextFromScheduler();
|
||||
}
|
||||
}
|
||||
else if (containsPhase(phase, { END_PRE, END_PRE_ALL, END_ACT }))
|
||||
else if(phase == END_REFB)
|
||||
{
|
||||
printDebugMessage("Finished auto refresh on bank " + to_string(bank.ID()));
|
||||
|
||||
if(numberOfPayloadsInSystem[bank] == 0)
|
||||
{
|
||||
controllerCore->powerDownManager->sleep(bank,sc_time_stamp());
|
||||
}
|
||||
else
|
||||
{
|
||||
scheduleNextFromScheduler(bank);
|
||||
}
|
||||
scheduleNextFromScheduler(bank);
|
||||
}
|
||||
else if (containsPhase(phase, { END_PRE, END_ACT }))
|
||||
{
|
||||
scheduleNextFromScheduler(bank);
|
||||
}
|
||||
else if(phase == END_PRE_ALL)
|
||||
{
|
||||
// No need to trigger anything for a END_PRE_ALL. It is followed by a AUTO_REFRESH anyway (in our current
|
||||
// scheduler implementation)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -7,9 +7,8 @@
|
||||
|
||||
#include "ControllerState.h"
|
||||
#include <algorithm>
|
||||
#include "TimingCalculation.h"
|
||||
#include "core/TimingCalculation.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
const ScheduledCommand ControllerState::getLastCommand(Command command, Bank bank) //TODO const reference? and make const
|
||||
{
|
||||
@@ -116,5 +115,3 @@ void ControllerState::cleanUp(sc_time time)
|
||||
if(time >= config->memSpec.tActHistory())
|
||||
lastActivates.erase(lastActivates.begin(), lastActivates.lower_bound(time - config->memSpec.tActHistory()));
|
||||
}
|
||||
|
||||
} /* namespace controller */
|
||||
@@ -10,15 +10,12 @@
|
||||
|
||||
#include <systemc.h>
|
||||
#include "RowBufferStates.h"
|
||||
#include "scheduling/ScheduledCommand.h"
|
||||
#include "Slots.h"
|
||||
#include "configuration/Configuration.h"
|
||||
#include "core/Slots.h"
|
||||
#include "core/configuration/Configuration.h"
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <list>
|
||||
|
||||
namespace core {
|
||||
|
||||
class ControllerState
|
||||
{
|
||||
public:
|
||||
@@ -54,6 +51,5 @@ private:
|
||||
Configuration* config;
|
||||
};
|
||||
|
||||
} /* namespace controller */
|
||||
|
||||
#endif /* CONTROLLER_STATE_H_ */
|
||||
23
dram/src/controller/IController.h
Normal file
23
dram/src/controller/IController.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef ICONTROLLER_H
|
||||
#define ICONTROLLER_H
|
||||
|
||||
|
||||
#include <systemc.h>
|
||||
#include "core/scheduling/ScheduledCommand.h"
|
||||
#include "core/scheduling/Trigger.h"
|
||||
|
||||
|
||||
// Utiliy class to pass around the Controller class to the controller Core and various schedulers, without having to propagate the template defintions
|
||||
// throughout all classes
|
||||
class IController
|
||||
{
|
||||
public:
|
||||
virtual ~IController() {}
|
||||
virtual void send(const ScheduledCommand& command,tlm::tlm_generic_payload& payload) = 0;
|
||||
virtual void send(Trigger trigger, sc_time time, tlm::tlm_generic_payload& payload) = 0;
|
||||
virtual void scheduleNextFromScheduler(Bank bank) = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // ICONTROLLER_H
|
||||
@@ -6,15 +6,12 @@
|
||||
*/
|
||||
|
||||
#include "RowBufferStates.h"
|
||||
#include "ControllerCore.h"
|
||||
#include "../../common/DebugManager.h"
|
||||
#include "../../common/Utils.h"
|
||||
#include "core/ControllerCore.h"
|
||||
#include "../common/DebugManager.h"
|
||||
#include "../common/Utils.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace core
|
||||
{
|
||||
|
||||
RowBufferState::RowBufferState()
|
||||
{
|
||||
closeAllRowBuffers();
|
||||
@@ -64,5 +61,4 @@ void RowBufferState::closeAllRowBuffers()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,10 +8,7 @@
|
||||
#ifndef ROWBUFFERSTATES_H_
|
||||
#define ROWBUFFERSTATES_H_
|
||||
#include <map>
|
||||
#include "../../common/dramExtension.h"
|
||||
|
||||
namespace core
|
||||
{
|
||||
#include "../common/dramExtension.h"
|
||||
|
||||
class RowBufferState {
|
||||
public:
|
||||
@@ -30,6 +27,4 @@ private:
|
||||
std::map<Bank,Row> rowsInRowBuffers;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* BANKSTATES_H_ */
|
||||
@@ -1,71 +0,0 @@
|
||||
#include "Command.h"
|
||||
#include <systemc.h>
|
||||
|
||||
namespace core {
|
||||
|
||||
std::string commandToString(Command command)
|
||||
{
|
||||
switch (command)
|
||||
{
|
||||
case Command::Read:
|
||||
return "RD";
|
||||
break;
|
||||
case Command::ReadA:
|
||||
return "RDA";
|
||||
break;
|
||||
case Command::Write:
|
||||
return "WR";
|
||||
break;
|
||||
case Command::WriteA:
|
||||
return "WRA";
|
||||
break;
|
||||
case Command::Precharge:
|
||||
return "PRE";
|
||||
break;
|
||||
case Command::Activate:
|
||||
return "ACT";
|
||||
break;
|
||||
case Command::PrechargeAll:
|
||||
return "PRE_ALL";
|
||||
break;
|
||||
case Command::AutoRefresh:
|
||||
return "AUTO_REFRESH";
|
||||
break;
|
||||
|
||||
case Command::PDNA:
|
||||
return "PDNA";
|
||||
break;
|
||||
case Command::PDNAX:
|
||||
return "PDNAX";
|
||||
break;
|
||||
case Command::PDNP:
|
||||
return "PDNP";
|
||||
break;
|
||||
case Command::PDNPX:
|
||||
return "PDNPX";
|
||||
break;
|
||||
case Command::SREF:
|
||||
return "SREF";
|
||||
break;
|
||||
case Command::SREFX:
|
||||
return "SREFX";
|
||||
break;
|
||||
|
||||
default:
|
||||
SC_REPORT_FATAL("command", "commandToString was called with unknown command");
|
||||
break;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
const std::vector<Command>& getAllCommands()
|
||||
{
|
||||
static std::vector<Command> allCommands( { Command::Precharge, Command::PrechargeAll,
|
||||
Command::Activate, Command::Read, Command::Write, Command::ReadA, Command::WriteA,
|
||||
Command::AutoRefresh, Command::PDNA, Command::PDNAX, Command::PDNP, Command::PDNPX,
|
||||
Command::SREF, Command::SREFX });
|
||||
return allCommands;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,13 +27,12 @@
|
||||
#include "../../common/DebugManager.h"
|
||||
|
||||
|
||||
namespace core {
|
||||
|
||||
std::string ControllerCore::senderName = "Controller Core";
|
||||
|
||||
ControllerCore::ControllerCore(IWrapperConnector& wrapperConnector, std::map<Bank, int>& numberOfPayloads) :
|
||||
config(Configuration::getInstance()), state(&config), wrapper(wrapperConnector), numberOfPayloads(
|
||||
numberOfPayloads), commandChecker(), savedState(&config), commandSequenceGenerator(state), commandSequenceScheduler(*this)
|
||||
ControllerCore::ControllerCore(IController& wrapperConnector, std::map<Bank, int>& numberOfPayloads) :
|
||||
config(Configuration::getInstance()), state(&config), controller(wrapperConnector), numberOfPayloads(
|
||||
numberOfPayloads), commandChecker()
|
||||
|
||||
{
|
||||
commandChecker[Command::Activate] = new ActivateChecker(config, state);
|
||||
@@ -92,16 +91,6 @@ ControllerCore::~ControllerCore()
|
||||
delete powerDownManager;
|
||||
}
|
||||
|
||||
void ControllerCore::saveState()
|
||||
{
|
||||
savedState = state;
|
||||
}
|
||||
|
||||
void ControllerCore::resetState()
|
||||
{
|
||||
state = savedState;
|
||||
}
|
||||
|
||||
void ControllerCore::triggerRefresh(tlm::tlm_generic_payload& payload)
|
||||
{
|
||||
sc_time time = sc_time_stamp();
|
||||
@@ -117,28 +106,28 @@ void ControllerCore::triggerRefresh(tlm::tlm_generic_payload& payload)
|
||||
}
|
||||
}
|
||||
|
||||
bool ControllerCore::scheduleRequest(tlm::tlm_generic_payload& payload)
|
||||
void ControllerCore::scheduleRequest(Command command, tlm::tlm_generic_payload &payload)
|
||||
{
|
||||
sc_time start = clkAlign(sc_time_stamp());
|
||||
state.cleanUp(start);
|
||||
|
||||
saveState();
|
||||
|
||||
CommandSequence sequence = commandSequenceGenerator.generateCommandSequence(payload);
|
||||
CommandSchedule schedule = commandSequenceScheduler.schedule(sequence, start, payload);
|
||||
|
||||
if (refreshManager->hasCollision(schedule))
|
||||
{
|
||||
resetState();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
send(schedule, payload);
|
||||
return true;
|
||||
}
|
||||
ScheduledCommand scheduledCommand = schedule(command, start, payload);
|
||||
state.change(scheduledCommand);
|
||||
controller.send(scheduledCommand, payload);
|
||||
}
|
||||
|
||||
ScheduledCommand ControllerCore::schedule(Command command, sc_time start,
|
||||
tlm::tlm_generic_payload& payload)
|
||||
{
|
||||
ControllerCore::printDebugMessage("Scheduling command " + commandToString(command) + " on " + DramExtension::getBank(payload).toString());
|
||||
ICommandChecker& checker = getCommandChecker(command);
|
||||
sc_time executionTime = getExecutionTime(command, payload);
|
||||
ScheduledCommand scheduledCommand(command, start, executionTime, DramExtension::getExtension(payload));
|
||||
checker.delayToSatisfyConstraints(scheduledCommand);
|
||||
return scheduledCommand;
|
||||
}
|
||||
|
||||
|
||||
bool ControllerCore::bankIsBusy(Bank bank)
|
||||
{
|
||||
sc_time time = sc_time_stamp();
|
||||
@@ -148,9 +137,10 @@ bool ControllerCore::bankIsBusy(Bank bank)
|
||||
return false;
|
||||
else if (lastScheduledCommand.commandIsIn( { Command::Write, Command::Read }))
|
||||
{
|
||||
// Read and writes can overlap, so the bank should not be busy during a rd/wr
|
||||
return (time < lastScheduledCommand.getStart());
|
||||
}
|
||||
else if (lastScheduledCommand.commandIsIn( { Command::WriteA, Command::ReadA }))
|
||||
else if (lastScheduledCommand.commandIsIn( { Command::WriteA, Command::ReadA, Command::Precharge, Command::PrechargeAll, Command::Activate }))
|
||||
{
|
||||
return (time < lastScheduledCommand.getEnd());
|
||||
}
|
||||
@@ -165,7 +155,7 @@ bool ControllerCore::bankIsBusy(Bank bank)
|
||||
}
|
||||
else
|
||||
{
|
||||
SC_REPORT_FATAL("Core", "Last command in command sequence was activate or precharge. This really doesn't make sense :D.");
|
||||
SC_REPORT_FATAL("Core", "Last command unkown");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -197,14 +187,6 @@ std::vector<Bank> ControllerCore::getFreeBanks()
|
||||
return freeBanks;
|
||||
}
|
||||
|
||||
void ControllerCore::send(const CommandSchedule& schedule, tlm::tlm_generic_payload& payload) const
|
||||
{
|
||||
for (const ScheduledCommand& cmd : schedule.getScheduledCommands())
|
||||
{
|
||||
wrapper.send(cmd, payload);
|
||||
}
|
||||
}
|
||||
|
||||
ICommandChecker& ControllerCore::getCommandChecker(Command command)
|
||||
{
|
||||
return *getElementFromMap(commandChecker, command);
|
||||
@@ -215,5 +197,4 @@ void ControllerCore::printDebugMessage(string message)
|
||||
DebugManager::getInstance().printDebugMessage(ControllerCore::senderName, message);
|
||||
}
|
||||
|
||||
} /* namespace controller */
|
||||
|
||||
|
||||
@@ -10,53 +10,46 @@
|
||||
|
||||
#include <tlm.h>
|
||||
#include <map>
|
||||
#include "IWrapperConnector.h"
|
||||
#include <utility>
|
||||
#include "../IController.h"
|
||||
#include "configuration/Configuration.h"
|
||||
#include "powerdown/PowerDownManager.h"
|
||||
#include "refresh/IRefreshManager.h"
|
||||
#include "scheduling/CommandSequenceGenerator.h"
|
||||
#include "scheduling/checker/ICommandChecker.h"
|
||||
#include "scheduling/CommandSequenceScheduler.h"
|
||||
#include "../../common/TlmRecorder.h"
|
||||
#include "../RowBufferStates.h"
|
||||
#include "../ControllerState.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
class ControllerCore
|
||||
{
|
||||
public:
|
||||
ControllerCore(IWrapperConnector& wrapper, std::map<Bank, int>& numberOfPayloads);
|
||||
ControllerCore(IController& controller, std::map<Bank, int>& numberOfPayloads);
|
||||
virtual ~ControllerCore() ;
|
||||
|
||||
bool scheduleRequest(tlm::tlm_generic_payload& payload);
|
||||
void scheduleRequest(Command command, tlm::tlm_generic_payload& payload);
|
||||
void triggerRefresh(tlm::tlm_generic_payload& payload);
|
||||
|
||||
const std::vector<Bank>& getBanks();
|
||||
std::vector<Bank> getFreeBanks();
|
||||
const RowBufferState& getRowBufferStates(){return state.rowBufferStates;}
|
||||
bool bankIsBusy(Bank bank);
|
||||
|
||||
ICommandChecker& getCommandChecker(Command command);
|
||||
static void printDebugMessage(string message);
|
||||
ICommandChecker& getCommandChecker(Command command); static void printDebugMessage(string message);
|
||||
|
||||
Configuration config;
|
||||
ControllerState state;
|
||||
IWrapperConnector& wrapper;
|
||||
IController& controller;
|
||||
IPowerDownManager* powerDownManager;
|
||||
IRefreshManager* refreshManager;
|
||||
std::map<Bank,int>& numberOfPayloads;
|
||||
static std::string senderName;
|
||||
|
||||
private:
|
||||
void send(const CommandSchedule& schedule, tlm::tlm_generic_payload& payload) const;
|
||||
bool bankIsBusy(Bank bank);
|
||||
void saveState();
|
||||
void resetState();
|
||||
|
||||
ScheduledCommand schedule(Command command, sc_time start, tlm::tlm_generic_payload &payload);
|
||||
std::map<Command, ICommandChecker*> commandChecker;
|
||||
ControllerState savedState;
|
||||
CommandSequenceGenerator commandSequenceGenerator;
|
||||
CommandSequenceScheduler commandSequenceScheduler;
|
||||
};
|
||||
|
||||
} /* namespace controller */
|
||||
|
||||
#endif /* CONTROLLER_H_ */
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* IInternalScheduler.h
|
||||
*
|
||||
* Created on: Mar 13, 2014
|
||||
* Author: jonny
|
||||
*/
|
||||
|
||||
#ifndef IINTERNALSCHEDULER_H_
|
||||
#define IINTERNALSCHEDULER_H_
|
||||
|
||||
#include <systemc.h>
|
||||
#include "scheduling/ScheduledCommand.h"
|
||||
#include "scheduling/Trigger.h"
|
||||
|
||||
namespace core
|
||||
{
|
||||
|
||||
class IWrapperConnector
|
||||
{
|
||||
public:
|
||||
virtual ~IWrapperConnector() {}
|
||||
virtual void send(const core::ScheduledCommand& command,tlm::tlm_generic_payload& payload) = 0;
|
||||
virtual void send(Trigger trigger, sc_time time, tlm::tlm_generic_payload& payload) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* IINTERNALSCHEDULER_H_ */
|
||||
@@ -8,7 +8,6 @@
|
||||
#include "Slots.h"
|
||||
#include "TimingCalculation.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
Slots::Slots(sc_time clk) :
|
||||
clk(clk)
|
||||
@@ -60,4 +59,3 @@ void Slots::blockSlots(sc_time begin, sc_time end, bool excludeBorders)
|
||||
|
||||
}
|
||||
|
||||
} /* namespace core */
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include <set>
|
||||
#include "scheduling/ScheduledCommand.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
class Slots
|
||||
{
|
||||
@@ -30,6 +29,5 @@ private:
|
||||
|
||||
};
|
||||
|
||||
} /* namespace core */
|
||||
|
||||
#endif /* SLOTS_H_ */
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "configuration/Configuration.h"
|
||||
#include "../../common/Utils.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
|
||||
sc_time getDelayToMeetConstraint(sc_time previous, sc_time start, sc_time constraint)
|
||||
@@ -129,5 +128,4 @@ sc_time getWriteAccessTime()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -11,10 +11,8 @@
|
||||
#include <systemc.h>
|
||||
#include <tlm.h>
|
||||
#include "../../common/dramExtension.h"
|
||||
#include "Command.h"
|
||||
#include "../Command.h"
|
||||
|
||||
namespace core
|
||||
{
|
||||
|
||||
sc_time getMinExecutionTimeForPowerDownCmd(Command command);
|
||||
sc_time getExecutionTime(Command command, tlm::tlm_generic_payload& payload);
|
||||
@@ -28,6 +26,4 @@ const sc_time clkAlign(sc_time time, Alignment alignment = UP);
|
||||
bool isClkAligned(sc_time time, sc_time clk);
|
||||
const sc_time FrequencyToClk(double frequencyMhz);
|
||||
|
||||
|
||||
}
|
||||
#endif /* UTILS_H_ */
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace core{
|
||||
|
||||
string Configuration::memspecUri = "";
|
||||
string Configuration::memconfigUri = "";
|
||||
|
||||
@@ -66,10 +64,6 @@ void Configuration::setParameter(std::string name, std::string value)
|
||||
BankwiseLogic = string2bool(value);
|
||||
else if(name == "OpenPagePolicy")
|
||||
OpenPagePolicy = string2bool(value);
|
||||
else if(name == "AdaptiveOpenPagePolicy")
|
||||
AdaptiveOpenPagePolicy = string2bool(value);
|
||||
else if(name == "RefreshAwareScheduling")
|
||||
RefreshAwareScheduling = string2bool(value);
|
||||
else if(name == "MaxNrOfTransactions")
|
||||
MaxNrOfTransactions = string2int(value);
|
||||
else if(name == "Scheduler")
|
||||
@@ -113,5 +107,4 @@ void Configuration::setParameters(std::map<std::string, std::string> parameterMa
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace core */
|
||||
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
#include <string>
|
||||
#include "MemSpec.h"
|
||||
|
||||
namespace core{
|
||||
|
||||
enum class EPowerDownMode{NoPowerDown, Staggered, TimeoutPDN, TimeoutSREF};
|
||||
|
||||
|
||||
@@ -31,8 +29,6 @@ struct Configuration
|
||||
//MemConfig
|
||||
bool BankwiseLogic = false;
|
||||
bool OpenPagePolicy = true;
|
||||
bool AdaptiveOpenPagePolicy = false;
|
||||
bool RefreshAwareScheduling = false;
|
||||
unsigned int MaxNrOfTransactions = 50;
|
||||
std::string Scheduler;
|
||||
unsigned int Capsize = 5;
|
||||
@@ -60,7 +56,5 @@ private:
|
||||
unsigned int powerDownTimeoutInClk = 3;
|
||||
};
|
||||
|
||||
} /* namespace core */
|
||||
|
||||
|
||||
#endif /* CONFIGURATION_H_ */
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
using namespace tinyxml2;
|
||||
using namespace std;
|
||||
|
||||
namespace core {
|
||||
|
||||
void ConfigurationLoader::loadSimConfig(Configuration& config, string simconfigUri)
|
||||
{
|
||||
tinyxml2::XMLDocument doc;
|
||||
@@ -23,28 +21,6 @@ void ConfigurationLoader::loadSimConfig(Configuration& config, string simconfigU
|
||||
loadConfig(config, simconfig);
|
||||
}
|
||||
|
||||
|
||||
void ConfigurationLoader::loadMemConfig(Configuration& config, string memconfigUri)
|
||||
{
|
||||
tinyxml2::XMLDocument doc;
|
||||
|
||||
loadXML(memconfigUri, doc);
|
||||
XMLElement* memconfig = doc.FirstChildElement("memconfig");
|
||||
loadConfig(config, memconfig);
|
||||
}
|
||||
|
||||
void ConfigurationLoader::loadMemConfig(Configuration& config, XMLElement* memconfig)
|
||||
{
|
||||
if(memconfig->Attribute("src"))
|
||||
{
|
||||
XMLDocument doc;
|
||||
string src(memconfig->Attribute("src"));
|
||||
loadXML(src, doc);
|
||||
loadMemConfig(config, doc.FirstChildElement("memconfig"));
|
||||
}
|
||||
loadConfig(config, memconfig);
|
||||
}
|
||||
|
||||
void ConfigurationLoader::loadSimConfig(Configuration& config, XMLElement* simconfig)
|
||||
{
|
||||
if(simconfig->Attribute("src"))
|
||||
@@ -103,6 +79,28 @@ void ConfigurationLoader::loadMemSpec(Configuration& config, XMLElement* memspec
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigurationLoader::loadMemConfig(Configuration& config, string memconfigUri)
|
||||
{
|
||||
tinyxml2::XMLDocument doc;
|
||||
|
||||
loadXML(memconfigUri, doc);
|
||||
XMLElement* memconfig = doc.FirstChildElement("memconfig");
|
||||
loadConfig(config, memconfig);
|
||||
}
|
||||
|
||||
void ConfigurationLoader::loadMemConfig(Configuration& config, XMLElement* memconfig)
|
||||
{
|
||||
if(memconfig->Attribute("src"))
|
||||
{
|
||||
XMLDocument doc;
|
||||
string src(memconfig->Attribute("src"));
|
||||
config.memconfigUri = src;
|
||||
loadXML(src, doc);
|
||||
loadMemConfig(config, doc.FirstChildElement("memconfig"));
|
||||
}
|
||||
loadConfig(config, memconfig);
|
||||
}
|
||||
|
||||
void ConfigurationLoader::loadDDR4(Configuration& config, XMLElement* memspec)
|
||||
{
|
||||
//MemArchitecture
|
||||
@@ -207,4 +205,3 @@ void ConfigurationLoader::loadWideIO(Configuration& config, XMLElement* memspec)
|
||||
|
||||
}
|
||||
|
||||
} /* namespace core */
|
||||
|
||||
@@ -13,8 +13,6 @@
|
||||
#include "../../../common/Utils.h"
|
||||
#include "Configuration.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
class ConfigurationLoader
|
||||
{
|
||||
public:
|
||||
@@ -35,6 +33,5 @@ private:
|
||||
static void loadWideIO(Configuration& config, tinyxml2::XMLElement* memspec);
|
||||
};
|
||||
|
||||
} /* namespace core */
|
||||
|
||||
#endif /* CONFIGURATIONLOADER_H_ */
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <map>
|
||||
#include "../../../common/dramExtension.h"
|
||||
|
||||
namespace core{
|
||||
|
||||
struct RefreshTiming
|
||||
{
|
||||
@@ -89,7 +88,6 @@ struct MemSpec
|
||||
sc_time tDataStrobeHistory(){return tWTR_L;}
|
||||
};
|
||||
|
||||
} /* namespace core */
|
||||
|
||||
|
||||
#endif /* MemSpec_H_ */
|
||||
|
||||
@@ -10,11 +10,9 @@
|
||||
|
||||
#include <systemc.h>
|
||||
#include "../../../common/dramExtension.h"
|
||||
#include "../Command.h"
|
||||
#include "../../Command.h"
|
||||
|
||||
|
||||
namespace core {
|
||||
|
||||
enum class PowerDownState
|
||||
{
|
||||
Awake, AwakeForRefresh, PDNActive, PDNPrecharge, PDNSelfRefresh
|
||||
@@ -99,6 +97,5 @@ inline std::string powerDownStateToString(PowerDownState powerDownState)
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace core */
|
||||
|
||||
#endif /* IPOWERDOWNMANAGER_H_ */
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
#include "NoPowerDown.h"
|
||||
|
||||
void core::NoPowerDown::triggerSleep(Bank /*bank*/, sc_time /*time*/)
|
||||
void NoPowerDown::triggerSleep(Bank /*bank*/, sc_time /*time*/)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void core::NoPowerDown::sleep(Bank /*bank*/, sc_time /*time*/)
|
||||
void NoPowerDown::sleep(Bank /*bank*/, sc_time /*time*/)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void core::NoPowerDown::wakeUp(Bank /*bank*/, sc_time /*time*/)
|
||||
void NoPowerDown::wakeUp(Bank /*bank*/, sc_time /*time*/)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void core::NoPowerDown::wakeUpForRefresh(Bank /*bank*/, sc_time /*time*/)
|
||||
void NoPowerDown::wakeUpForRefresh(Bank /*bank*/, sc_time /*time*/)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool core::NoPowerDown::isInSelfRefresh(Bank /*bank*/)
|
||||
bool NoPowerDown::isInSelfRefresh(Bank /*bank*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "../scheduling/ScheduledCommand.h"
|
||||
|
||||
|
||||
namespace core {
|
||||
|
||||
class NoPowerDown: public IPowerDownManager
|
||||
{
|
||||
@@ -32,6 +31,6 @@ public:
|
||||
virtual bool isInSelfRefresh(Bank bank) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // NOPOWERDOWN_H
|
||||
|
||||
@@ -17,10 +17,9 @@
|
||||
using namespace tlm;
|
||||
using namespace std;
|
||||
|
||||
namespace core {
|
||||
|
||||
PowerDownManager::PowerDownManager(ControllerCore& controller) :
|
||||
controller(controller)
|
||||
controllerCore(controller)
|
||||
{
|
||||
powerDownState = PowerDownState::Awake;
|
||||
for (Bank bank : controller.getBanks())
|
||||
@@ -43,14 +42,14 @@ void PowerDownManager::sleep(Bank bank, sc_time time)
|
||||
|
||||
if (state == PowerDownState::Awake) //coming from active
|
||||
{
|
||||
state = controller.state.rowBufferStates.allRowBuffersAreClosed() ? PowerDownState::PDNPrecharge : PowerDownState::PDNActive;
|
||||
state = controllerCore.state.rowBufferStates.allRowBuffersAreClosed() ? PowerDownState::PDNPrecharge : PowerDownState::PDNActive;
|
||||
}
|
||||
else if (state == PowerDownState::AwakeForRefresh) //coming from refresh interrupting power down
|
||||
{
|
||||
sc_assert(controller.state.rowBufferStates.allRowBuffersAreClosed());
|
||||
sc_assert(controllerCore.state.rowBufferStates.allRowBuffersAreClosed());
|
||||
|
||||
if (controller.state.getLastCommand(Command::PDNA).getStart()
|
||||
>= controller.state.getLastCommand(Command::PDNP).getStart())
|
||||
if (controllerCore.state.getLastCommand(Command::PDNA).getStart()
|
||||
>= controllerCore.state.getLastCommand(Command::PDNP).getStart())
|
||||
state = PowerDownState::PDNPrecharge;
|
||||
else
|
||||
{
|
||||
@@ -62,9 +61,9 @@ void PowerDownManager::sleep(Bank bank, sc_time time)
|
||||
ScheduledCommand pdn(cmd, time, getMinExecutionTimeForPowerDownCmd(cmd),
|
||||
DramExtension::getExtension(powerDownPayloads[bank]));
|
||||
|
||||
controller.getCommandChecker(cmd).delayToSatisfyConstraints(pdn);
|
||||
controllerCore.getCommandChecker(cmd).delayToSatisfyConstraints(pdn);
|
||||
|
||||
if (state != PowerDownState::PDNSelfRefresh && controller.refreshManager->hasCollision(pdn))
|
||||
if (state != PowerDownState::PDNSelfRefresh && controllerCore.refreshManager->hasCollision(pdn))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -86,10 +85,10 @@ void PowerDownManager::wakeUp(Bank bank, sc_time time)
|
||||
Command cmd = IPowerDownManager::getWakeUpCommand(powerDownState);
|
||||
ScheduledCommand pdn(cmd, time, getExecutionTime(cmd, powerDownPayloads[bank]),
|
||||
DramExtension::getExtension(powerDownPayloads[bank]));
|
||||
controller.getCommandChecker(cmd).delayToSatisfyConstraints(pdn);
|
||||
controllerCore.getCommandChecker(cmd).delayToSatisfyConstraints(pdn);
|
||||
|
||||
if (cmd == Command::SREFX)
|
||||
controller.refreshManager->reInitialize(bank, pdn.getEnd());
|
||||
controllerCore.refreshManager->reInitialize(bank, pdn.getEnd());
|
||||
|
||||
setPowerDownState(PowerDownState::Awake);
|
||||
sendPowerDownPayloads(pdn);
|
||||
@@ -111,14 +110,15 @@ void PowerDownManager::wakeUpForRefresh(Bank bank, sc_time time)
|
||||
|
||||
void PowerDownManager::sendPowerDownPayloads(ScheduledCommand& cmd)
|
||||
{
|
||||
controller.state.bus.moveCommandToNextFreeSlot(cmd);
|
||||
for (Bank bank : controller.getBanks())
|
||||
controllerCore.state.bus.moveCommandToNextFreeSlot(cmd);
|
||||
for (Bank bank : controllerCore.getBanks())
|
||||
{
|
||||
tlm_generic_payload& payloadToSend = powerDownPayloads[bank];
|
||||
|
||||
ScheduledCommand pdnToSend(cmd.getCommand(), cmd.getStart(), cmd.getExecutionTime(),
|
||||
DramExtension::getExtension(payloadToSend));
|
||||
controller.state.change(pdnToSend);
|
||||
controller.wrapper.send(pdnToSend, payloadToSend);
|
||||
controllerCore.state.change(pdnToSend);
|
||||
controllerCore.controller.send(pdnToSend, payloadToSend);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,9 +137,9 @@ bool PowerDownManager::isInPowerDown()
|
||||
|
||||
bool PowerDownManager::canSleep()
|
||||
{
|
||||
for (Bank bank : controller.getBanks())
|
||||
for (Bank bank : controllerCore.getBanks())
|
||||
{
|
||||
if (!controller.numberOfPayloads[bank] == 0)
|
||||
if (!controllerCore.numberOfPayloads[bank] == 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -160,6 +160,5 @@ void PowerDownManager::triggerSleep(Bank bank, sc_time time)
|
||||
sleep(bank, time);
|
||||
}
|
||||
|
||||
} /* namespace core */
|
||||
|
||||
|
||||
|
||||
@@ -10,14 +10,13 @@
|
||||
|
||||
#include "PowerDownManagerBankwise.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
class ControllerCore;
|
||||
|
||||
class PowerDownManager: public IPowerDownManager
|
||||
{
|
||||
public:
|
||||
PowerDownManager(ControllerCore& controller);
|
||||
PowerDownManager(ControllerCore& controllerCore);
|
||||
virtual ~PowerDownManager();
|
||||
|
||||
virtual void triggerSleep(Bank bank, sc_time time) override;
|
||||
@@ -35,9 +34,8 @@ private:
|
||||
|
||||
PowerDownState powerDownState;
|
||||
std::map<Bank, tlm::tlm_generic_payload> powerDownPayloads;
|
||||
ControllerCore& controller;
|
||||
ControllerCore& controllerCore;
|
||||
};
|
||||
|
||||
} /* namespace core */
|
||||
|
||||
#endif /* POWERDOWNMANAGER_H_ */
|
||||
|
||||
@@ -12,12 +12,11 @@
|
||||
|
||||
using namespace tlm;
|
||||
|
||||
namespace core {
|
||||
|
||||
std::string PowerDownManagerBankwise::senderName = "pdn manager";
|
||||
|
||||
PowerDownManagerBankwise::PowerDownManagerBankwise(ControllerCore& controller) :
|
||||
controller(controller)
|
||||
controllerCore(controller)
|
||||
{
|
||||
for (Bank bank : controller.getBanks())
|
||||
{
|
||||
@@ -36,14 +35,14 @@ void PowerDownManagerBankwise::sleep(Bank bank, sc_time time)
|
||||
PowerDownState state = powerDownStates[bank];
|
||||
if (state == PowerDownState::Awake) //coming from active
|
||||
{
|
||||
state = controller.state.rowBufferStates.rowBufferIsOpen(bank) ? PowerDownState::PDNActive : PowerDownState::PDNPrecharge;
|
||||
state = controllerCore.state.rowBufferStates.rowBufferIsOpen(bank) ? PowerDownState::PDNActive : PowerDownState::PDNPrecharge;
|
||||
}
|
||||
else if (state == PowerDownState::AwakeForRefresh) //coming from refresh interrupting power down
|
||||
{
|
||||
sc_assert(!controller.state.rowBufferStates.rowBufferIsOpen(bank));
|
||||
sc_assert(!controllerCore.state.rowBufferStates.rowBufferIsOpen(bank));
|
||||
|
||||
if (controller.state.getLastCommand(Command::PDNA, bank).getStart()
|
||||
>= controller.state.getLastCommand(Command::PDNP, bank).getStart())
|
||||
if (controllerCore.state.getLastCommand(Command::PDNA, bank).getStart()
|
||||
>= controllerCore.state.getLastCommand(Command::PDNP, bank).getStart())
|
||||
state = PowerDownState::PDNPrecharge;
|
||||
else
|
||||
{
|
||||
@@ -53,9 +52,9 @@ void PowerDownManagerBankwise::sleep(Bank bank, sc_time time)
|
||||
|
||||
Command cmd = IPowerDownManager::getSleepCommand(state);
|
||||
ScheduledCommand pdn(cmd, time, getMinExecutionTimeForPowerDownCmd(cmd), DramExtension::getExtension(payload));
|
||||
controller.getCommandChecker(cmd).delayToSatisfyConstraints(pdn);
|
||||
controllerCore.getCommandChecker(cmd).delayToSatisfyConstraints(pdn);
|
||||
|
||||
if (state != PowerDownState::PDNSelfRefresh && controller.refreshManager->hasCollision(pdn))
|
||||
if (state != PowerDownState::PDNSelfRefresh && controllerCore.refreshManager->hasCollision(pdn))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -78,10 +77,10 @@ void PowerDownManagerBankwise::wakeUp(Bank bank, sc_time time)
|
||||
Command cmd = IPowerDownManager::getWakeUpCommand(powerDownStates[bank]);
|
||||
ScheduledCommand pdn(cmd, time, getExecutionTime(cmd, powerDownPayloads[bank]),
|
||||
DramExtension::getExtension(powerDownPayloads[bank]));
|
||||
controller.getCommandChecker(cmd).delayToSatisfyConstraints(pdn);
|
||||
controllerCore.getCommandChecker(cmd).delayToSatisfyConstraints(pdn);
|
||||
|
||||
if (cmd == Command::SREFX)
|
||||
controller.refreshManager->reInitialize(bank, pdn.getEnd());
|
||||
controllerCore.refreshManager->reInitialize(bank, pdn.getEnd());
|
||||
|
||||
setState(PowerDownState::Awake, bank);
|
||||
sendPowerDownPayload(pdn);
|
||||
@@ -133,14 +132,14 @@ void PowerDownManagerBankwise::setState(PowerDownState state, Bank bank)
|
||||
|
||||
void PowerDownManagerBankwise::sendPowerDownPayload(ScheduledCommand& pdn)
|
||||
{
|
||||
controller.state.bus.moveCommandToNextFreeSlot(pdn);
|
||||
controller.state.change(pdn);
|
||||
controller.wrapper.send(pdn, powerDownPayloads[pdn.getBank()]);
|
||||
controllerCore.state.bus.moveCommandToNextFreeSlot(pdn);
|
||||
controllerCore.state.change(pdn);
|
||||
controllerCore.controller.send(pdn, powerDownPayloads[pdn.getBank()]);
|
||||
}
|
||||
|
||||
bool PowerDownManagerBankwise::canSleep(Bank bank)
|
||||
{
|
||||
return controller.numberOfPayloads[bank] == 0;
|
||||
return controllerCore.numberOfPayloads[bank] == 0;
|
||||
}
|
||||
|
||||
void PowerDownManagerBankwise::triggerSleep(Bank bank, sc_time time)
|
||||
@@ -148,6 +147,5 @@ void PowerDownManagerBankwise::triggerSleep(Bank bank, sc_time time)
|
||||
sleep(bank, time);
|
||||
}
|
||||
|
||||
}/* namespace core */
|
||||
|
||||
|
||||
|
||||
@@ -12,19 +12,18 @@
|
||||
#include <tlm.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include "../Command.h"
|
||||
#include "../../Command.h"
|
||||
#include "../../../common/dramExtension.h"
|
||||
#include "../scheduling/ScheduledCommand.h"
|
||||
#include "IPowerDownManager.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
class ControllerCore;
|
||||
|
||||
class PowerDownManagerBankwise: public IPowerDownManager
|
||||
{
|
||||
public:
|
||||
PowerDownManagerBankwise(ControllerCore& controller);
|
||||
PowerDownManagerBankwise(ControllerCore& controllerCore);
|
||||
virtual ~PowerDownManagerBankwise()
|
||||
{
|
||||
}
|
||||
@@ -41,7 +40,7 @@ private:
|
||||
virtual bool isAwake(Bank bank);
|
||||
virtual bool isAwakeForRefresh(Bank bank);
|
||||
|
||||
ControllerCore& controller;
|
||||
ControllerCore& controllerCore;
|
||||
std::map<Bank, tlm::tlm_generic_payload> powerDownPayloads;
|
||||
std::map<Bank, PowerDownState> powerDownStates;
|
||||
|
||||
@@ -55,6 +54,5 @@ private:
|
||||
void sendPowerDownPayload(ScheduledCommand& pdn);
|
||||
};
|
||||
|
||||
}/* namespace core */
|
||||
|
||||
#endif /* POWERDOWNMANAGERBANKWISE_H_ */
|
||||
|
||||
@@ -12,9 +12,8 @@
|
||||
|
||||
using namespace tlm;
|
||||
|
||||
namespace core {
|
||||
|
||||
PowerDownManagerTimeout::PowerDownManagerTimeout(ControllerCore& controller): controller(controller)
|
||||
PowerDownManagerTimeout::PowerDownManagerTimeout(ControllerCore& controller): controllerCore(controller)
|
||||
{
|
||||
for (Bank bank : controller.getBanks())
|
||||
{
|
||||
@@ -29,12 +28,12 @@ PowerDownManagerTimeout::~PowerDownManagerTimeout()
|
||||
|
||||
void PowerDownManagerTimeout::sleep(Bank bank, sc_time time)
|
||||
{
|
||||
if(canSleep() && !isInPowerDown() && (time - controller.state.getLastScheduledCommand().getEnd()) >= Configuration::getInstance().getPowerDownTimeout())
|
||||
if(canSleep() && !isInPowerDown() && (time - controllerCore.state.getLastScheduledCommand().getEnd()) >= Configuration::getInstance().getPowerDownTimeout())
|
||||
{
|
||||
PowerDownState newState;
|
||||
if(Configuration::getInstance().PowerDownMode == EPowerDownMode::TimeoutPDN)
|
||||
{
|
||||
newState = controller.state.rowBufferStates.allRowBuffersAreClosed() ? PowerDownState::PDNPrecharge : PowerDownState::PDNActive;
|
||||
newState = controllerCore.state.rowBufferStates.allRowBuffersAreClosed() ? PowerDownState::PDNPrecharge : PowerDownState::PDNActive;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -45,9 +44,9 @@ void PowerDownManagerTimeout::sleep(Bank bank, sc_time time)
|
||||
ScheduledCommand pdn(cmd, time, getMinExecutionTimeForPowerDownCmd(cmd),
|
||||
DramExtension::getExtension(powerDownPayloads[bank]));
|
||||
|
||||
controller.getCommandChecker(cmd).delayToSatisfyConstraints(pdn);
|
||||
controllerCore.getCommandChecker(cmd).delayToSatisfyConstraints(pdn);
|
||||
|
||||
if (controller.refreshManager->hasCollision(pdn))
|
||||
if (controllerCore.refreshManager->hasCollision(pdn))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -79,10 +78,10 @@ void PowerDownManagerTimeout::wakeUp(Bank bank, sc_time time)
|
||||
Command cmd = IPowerDownManager::getWakeUpCommand(powerDownState);
|
||||
ScheduledCommand pdn(cmd, time, getExecutionTime(cmd, powerDownPayloads[bank]),
|
||||
DramExtension::getExtension(powerDownPayloads[bank]));
|
||||
controller.getCommandChecker(cmd).delayToSatisfyConstraints(pdn);
|
||||
controllerCore.getCommandChecker(cmd).delayToSatisfyConstraints(pdn);
|
||||
|
||||
if (cmd == Command::SREFX)
|
||||
controller.refreshManager->reInitialize(bank, pdn.getEnd());
|
||||
controllerCore.refreshManager->reInitialize(bank, pdn.getEnd());
|
||||
|
||||
setPowerDownState(PowerDownState::Awake);
|
||||
sendPowerDownPayloads(pdn);
|
||||
@@ -106,7 +105,7 @@ void PowerDownManagerTimeout::triggerSleep(Bank /*bank*/, sc_time time)
|
||||
{
|
||||
if(canSleep() && !isInPowerDown())
|
||||
{
|
||||
controller.wrapper.send(PDNTrigger, time + controller.config.getPowerDownTimeout(), powerDownPayloads[Bank(0)]);
|
||||
controllerCore.controller.send(PDNTrigger, time + controllerCore.config.getPowerDownTimeout(), powerDownPayloads[Bank(0)]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,9 +116,9 @@ bool PowerDownManagerTimeout::isInSelfRefresh(Bank /*bank*/)
|
||||
|
||||
bool PowerDownManagerTimeout::canSleep()
|
||||
{
|
||||
for (Bank bank : controller.getBanks())
|
||||
for (Bank bank : controllerCore.getBanks())
|
||||
{
|
||||
if (!controller.numberOfPayloads[bank] == 0)
|
||||
if (!controllerCore.numberOfPayloads[bank] == 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -127,15 +126,14 @@ bool PowerDownManagerTimeout::canSleep()
|
||||
|
||||
void PowerDownManagerTimeout::sendPowerDownPayloads(ScheduledCommand& cmd)
|
||||
{
|
||||
controller.state.bus.moveCommandToNextFreeSlot(cmd);
|
||||
for (Bank bank : controller.getBanks())
|
||||
controllerCore.state.bus.moveCommandToNextFreeSlot(cmd);
|
||||
for (Bank bank : controllerCore.getBanks())
|
||||
{
|
||||
tlm_generic_payload& payloadToSend = powerDownPayloads[bank];
|
||||
ScheduledCommand pdnToSend(cmd.getCommand(), cmd.getStart(), cmd.getExecutionTime(),
|
||||
DramExtension::getExtension(payloadToSend));
|
||||
controller.state.change(pdnToSend);
|
||||
controller.wrapper.send(pdnToSend, payloadToSend);
|
||||
controllerCore.state.change(pdnToSend);
|
||||
controllerCore.controller.send(pdnToSend, payloadToSend);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,13 +14,12 @@
|
||||
#include "../scheduling/ScheduledCommand.h"
|
||||
#include <map>
|
||||
|
||||
namespace core {
|
||||
class ControllerCore;
|
||||
|
||||
class PowerDownManagerTimeout: public core::IPowerDownManager
|
||||
class PowerDownManagerTimeout: public IPowerDownManager
|
||||
{
|
||||
public:
|
||||
PowerDownManagerTimeout(ControllerCore& controller);
|
||||
PowerDownManagerTimeout(ControllerCore& controllerCore);
|
||||
virtual ~PowerDownManagerTimeout();
|
||||
|
||||
virtual void triggerSleep(Bank bank, sc_time time);
|
||||
@@ -32,7 +31,7 @@ public:
|
||||
virtual bool isInSelfRefresh(Bank bank);
|
||||
private:
|
||||
bool canSleep();
|
||||
ControllerCore& controller;
|
||||
ControllerCore& controllerCore;
|
||||
|
||||
std::map<Bank, tlm::tlm_generic_payload> powerDownPayloads;
|
||||
void sendPowerDownPayloads(ScheduledCommand& cmd);
|
||||
@@ -42,6 +41,6 @@ private:
|
||||
bool isInPowerDown();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif /* POWERDOWNMANAGERTIMEOUT_H_ */
|
||||
|
||||
@@ -2,15 +2,13 @@
|
||||
#define IREFRESHMANAGER_H_
|
||||
|
||||
#include <systemc.h>
|
||||
#include "../scheduling/CommandSchedule.h"
|
||||
#include "../scheduling/ScheduledCommand.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
class IRefreshManager
|
||||
{
|
||||
public:
|
||||
virtual ~IRefreshManager(){};
|
||||
virtual bool hasCollision(const CommandSchedule& schedule) = 0;
|
||||
virtual bool hasCollision(const ScheduledCommand& command) = 0;
|
||||
virtual void scheduleRefresh(tlm::tlm_generic_payload& payload, sc_time time) = 0;
|
||||
virtual void reInitialize(Bank bank, sc_time time) = 0;
|
||||
@@ -19,6 +17,5 @@ public:
|
||||
virtual bool isInvalidated(tlm::tlm_generic_payload& payload, sc_time time) = 0;
|
||||
};
|
||||
|
||||
} // namespace core
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,12 +12,14 @@
|
||||
#include "../TimingCalculation.h"
|
||||
|
||||
using namespace tlm;
|
||||
namespace core {
|
||||
|
||||
RefreshManager::RefreshManager(ControllerCore& controller) :
|
||||
controller(controller), timing(controller.config.memSpec.refreshTimings[Bank(0)]), nextPlannedRefresh(SC_ZERO_TIME)
|
||||
controllerCore(controller), timing(controller.config.memSpec.refreshTimings[Bank(0)]), nextPlannedRefresh(SC_ZERO_TIME)
|
||||
{
|
||||
setupTransactions();
|
||||
for (Bank bank : controller.getBanks())
|
||||
{
|
||||
setUpDummy(refreshPayloads[bank], bank);
|
||||
}
|
||||
planNextRefresh();
|
||||
}
|
||||
|
||||
@@ -25,58 +27,48 @@ RefreshManager::~RefreshManager()
|
||||
{
|
||||
}
|
||||
|
||||
bool RefreshManager::hasCollision(const CommandSchedule& schedule)
|
||||
{
|
||||
return schedule.getStart() < controller.state.getLastCommand(Command::AutoRefresh).getEnd() || schedule.getEnd() > nextPlannedRefresh;
|
||||
}
|
||||
|
||||
bool RefreshManager::hasCollision(const ScheduledCommand& command)
|
||||
{
|
||||
|
||||
return command.getStart() < controller.state.getLastCommand(Command::AutoRefresh).getEnd() || command.getEnd() > nextPlannedRefresh;
|
||||
return command.getStart() < controllerCore.state.getLastCommand(Command::AutoRefresh).getEnd() || command.getEnd() > nextPlannedRefresh;
|
||||
}
|
||||
|
||||
void RefreshManager::scheduleRefresh(tlm::tlm_generic_payload& payload, sc_time time)
|
||||
{
|
||||
sc_assert(!isInvalidated(payload, time));
|
||||
|
||||
if (!controller.state.rowBufferStates.allRowBuffersAreClosed())
|
||||
if (!controllerCore.state.rowBufferStates.allRowBuffersAreClosed())
|
||||
{
|
||||
ScheduledCommand precharge(Command::PrechargeAll, time, getExecutionTime(Command::PrechargeAll, refreshPayloads[Bank(0)]),
|
||||
DramExtension::getExtension(refreshPayloads[Bank(0)]));
|
||||
controller.getCommandChecker(Command::PrechargeAll).delayToSatisfyConstraints(precharge);
|
||||
sendToAllBanks(precharge);
|
||||
ScheduledCommand prechargeAllMaster(Command::PrechargeAll, time, getExecutionTime(Command::PrechargeAll, refreshPayloads[Bank(0)]),
|
||||
refreshPayloads[Bank(0)]);
|
||||
controllerCore.getCommandChecker(Command::PrechargeAll).delayToSatisfyConstraints(prechargeAllMaster);
|
||||
|
||||
for (Bank bank : controllerCore.getBanks())
|
||||
{
|
||||
ScheduledCommand prechargeAll(Command::PrechargeAll, prechargeAllMaster.getStart(), prechargeAllMaster.getExecutionTime(),
|
||||
refreshPayloads[bank]);
|
||||
controllerCore.state.change(prechargeAll);
|
||||
controllerCore.controller.send(prechargeAll, refreshPayloads[bank]);
|
||||
}
|
||||
}
|
||||
|
||||
ScheduledCommand nextRefresh(Command::AutoRefresh, time, getExecutionTime(Command::AutoRefresh, refreshPayloads[Bank(0)]),
|
||||
DramExtension::getExtension(refreshPayloads[Bank(0)]));
|
||||
controller.getCommandChecker(Command::AutoRefresh).delayToSatisfyConstraints(nextRefresh);
|
||||
sendToAllBanks(nextRefresh);
|
||||
|
||||
for (Bank bank : controller.getBanks())
|
||||
for (Bank bank : controllerCore.getBanks())
|
||||
{
|
||||
ScheduledCommand refresh(Command::AutoRefresh, time, getExecutionTime(Command::AutoRefresh, refreshPayloads[bank]),
|
||||
DramExtension::getExtension(refreshPayloads[bank]));
|
||||
controllerCore.getCommandChecker(Command::AutoRefresh).delayToSatisfyConstraints(refresh);
|
||||
controllerCore.state.change(refresh);
|
||||
controllerCore.controller.send(refresh, refreshPayloads[bank]);
|
||||
|
||||
DramExtension::getExtension(refreshPayloads[bank]).incrementRow();
|
||||
}
|
||||
|
||||
planNextRefresh();
|
||||
}
|
||||
|
||||
void RefreshManager::sendToAllBanks(ScheduledCommand& command)
|
||||
{
|
||||
for (Bank bank : controller.getBanks())
|
||||
{
|
||||
tlm_generic_payload& payload = refreshPayloads[bank];
|
||||
DramExtension extension = DramExtension::getExtension(payload);
|
||||
ScheduledCommand cmd(command.getCommand(), command.getStart(), command.getExecutionTime(), extension);
|
||||
controller.state.change(cmd);
|
||||
controller.wrapper.send(cmd, payload);
|
||||
}
|
||||
}
|
||||
|
||||
void RefreshManager::planNextRefresh()
|
||||
{
|
||||
nextPlannedRefresh += timing.tREFI;
|
||||
controller.wrapper.send(REFTrigger, nextPlannedRefresh, refreshPayloads[Bank(0)]);
|
||||
controllerCore.controller.send(REFTrigger, nextPlannedRefresh, refreshPayloads[Bank(0)]);
|
||||
}
|
||||
|
||||
void RefreshManager::reInitialize(Bank /*bank*/, sc_time time)
|
||||
@@ -85,17 +77,8 @@ void RefreshManager::reInitialize(Bank /*bank*/, sc_time time)
|
||||
planNextRefresh();
|
||||
}
|
||||
|
||||
bool core::RefreshManager::isInvalidated(tlm::tlm_generic_payload& payload, sc_time time)
|
||||
bool RefreshManager::isInvalidated(tlm::tlm_generic_payload& payload, sc_time time)
|
||||
{
|
||||
return nextPlannedRefresh > time;
|
||||
}
|
||||
|
||||
void RefreshManager::setupTransactions()
|
||||
{
|
||||
for (Bank bank : controller.getBanks())
|
||||
{
|
||||
setUpDummy(refreshPayloads[bank], bank);
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace core */
|
||||
|
||||
@@ -11,35 +11,28 @@
|
||||
#include "IRefreshManager.h"
|
||||
#include "../configuration/MemSpec.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
class ControllerCore;
|
||||
|
||||
class RefreshManager : public IRefreshManager
|
||||
{
|
||||
public:
|
||||
RefreshManager(ControllerCore& controller);
|
||||
RefreshManager(ControllerCore& controllerCore);
|
||||
virtual ~RefreshManager();
|
||||
|
||||
virtual bool hasCollision(const CommandSchedule& schedule) override;
|
||||
virtual bool hasCollision(const ScheduledCommand& command) override;
|
||||
|
||||
virtual void scheduleRefresh(tlm::tlm_generic_payload& payload, sc_time time) override;
|
||||
void reInitialize(Bank bank, sc_time time) override;
|
||||
virtual bool isInvalidated(tlm::tlm_generic_payload& payload, sc_time time) override;
|
||||
|
||||
private:
|
||||
ControllerCore& controller;
|
||||
ControllerCore& controllerCore;
|
||||
RefreshTiming& timing;
|
||||
sc_time nextPlannedRefresh;
|
||||
std::map<Bank, tlm::tlm_generic_payload> refreshPayloads;
|
||||
|
||||
void planNextRefresh();
|
||||
|
||||
void sendToAllBanks(ScheduledCommand& command);
|
||||
void setupTransactions();
|
||||
};
|
||||
|
||||
} /* namespace core */
|
||||
|
||||
#endif /* REFRESHMANAGER_H_ */
|
||||
|
||||
@@ -12,10 +12,9 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace core {
|
||||
|
||||
RefreshManagerBankwise::RefreshManagerBankwise(ControllerCore& controller) :
|
||||
controller(controller)
|
||||
controllerCore(controller)
|
||||
{
|
||||
for (Bank bank : controller.getBanks())
|
||||
{
|
||||
@@ -28,15 +27,9 @@ RefreshManagerBankwise::~RefreshManagerBankwise()
|
||||
{
|
||||
}
|
||||
|
||||
bool RefreshManagerBankwise::hasCollision(const CommandSchedule& schedule)
|
||||
{
|
||||
return schedule.getStart() < controller.state.getLastCommand(Command::AutoRefresh, schedule.getBank()).getEnd()
|
||||
|| schedule.getEnd() > nextPlannedRefreshs[schedule.getBank()];
|
||||
}
|
||||
|
||||
bool RefreshManagerBankwise::hasCollision(const ScheduledCommand& command)
|
||||
{
|
||||
return command.getStart() < controller.state.getLastCommand(Command::AutoRefresh, command.getBank()).getEnd()
|
||||
return command.getStart() < controllerCore.state.getLastCommand(Command::AutoRefresh, command.getBank()).getEnd()
|
||||
|| command.getEnd() > nextPlannedRefreshs[command.getBank()];}
|
||||
|
||||
void RefreshManagerBankwise::scheduleRefresh(tlm::tlm_generic_payload& payload, sc_time time)
|
||||
@@ -47,19 +40,19 @@ void RefreshManagerBankwise::scheduleRefresh(tlm::tlm_generic_payload& payload,
|
||||
|
||||
DramExtension& extension = DramExtension::getExtension(refreshPayload);
|
||||
|
||||
if (controller.state.rowBufferStates.rowBufferIsOpen(extension.getBank()))
|
||||
if (controllerCore.state.rowBufferStates.rowBufferIsOpen(extension.getBank()))
|
||||
{
|
||||
ScheduledCommand precharge(Command::Precharge, time, getExecutionTime(Command::Precharge, refreshPayload), extension);
|
||||
|
||||
controller.getCommandChecker(Command::Precharge).delayToSatisfyConstraints(precharge);
|
||||
controller.state.change(precharge);
|
||||
controller.wrapper.send(precharge, refreshPayload);
|
||||
controllerCore.getCommandChecker(Command::Precharge).delayToSatisfyConstraints(precharge);
|
||||
controllerCore.state.change(precharge);
|
||||
controllerCore.controller.send(precharge, refreshPayload);
|
||||
}
|
||||
|
||||
ScheduledCommand nextRefresh(Command::AutoRefresh, time, getExecutionTime(Command::AutoRefresh, refreshPayload), extension);
|
||||
controller.getCommandChecker(Command::AutoRefresh).delayToSatisfyConstraints(nextRefresh);
|
||||
controller.state.change(nextRefresh);
|
||||
controller.wrapper.send(nextRefresh, refreshPayload);
|
||||
ScheduledCommand refresh(Command::AutoRefresh, time, getExecutionTime(Command::AutoRefresh, refreshPayload), extension);
|
||||
controllerCore.getCommandChecker(Command::AutoRefresh).delayToSatisfyConstraints(refresh);
|
||||
controllerCore.state.change(refresh);
|
||||
controllerCore.controller.send(refresh, refreshPayload);
|
||||
|
||||
extension.incrementRow();
|
||||
planNextRefresh(extension.getBank());
|
||||
@@ -68,7 +61,7 @@ void RefreshManagerBankwise::scheduleRefresh(tlm::tlm_generic_payload& payload,
|
||||
void RefreshManagerBankwise::planNextRefresh(Bank bank)
|
||||
{
|
||||
nextPlannedRefreshs[bank] += Configuration::getInstance().memSpec.refreshTimings[bank].tREFI;
|
||||
controller.wrapper.send(REFTrigger, nextPlannedRefreshs[bank], refreshPayloads[bank]);
|
||||
controllerCore.controller.send(REFTrigger, nextPlannedRefreshs[bank], refreshPayloads[bank]);
|
||||
}
|
||||
|
||||
void RefreshManagerBankwise::reInitialize(Bank bank, sc_time time)
|
||||
@@ -82,5 +75,4 @@ bool RefreshManagerBankwise::isInvalidated(tlm::tlm_generic_payload& payload, sc
|
||||
return nextPlannedRefreshs[DramExtension::getExtension(payload).getBank()] > time;
|
||||
}
|
||||
|
||||
} /* namespace core */
|
||||
|
||||
|
||||
@@ -8,23 +8,20 @@
|
||||
#ifndef BANKWISEREFRESHMANAGER_H_
|
||||
#define BANKWISEREFRESHMANAGER_H_
|
||||
|
||||
#include "../scheduling/CommandSchedule.h"
|
||||
#include "../../../common/dramExtension.h"
|
||||
#include "../configuration/MemSpec.h"
|
||||
#include "IRefreshManager.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
class ControllerCore;
|
||||
|
||||
class RefreshManagerBankwise : public IRefreshManager
|
||||
{
|
||||
public:
|
||||
RefreshManagerBankwise(ControllerCore& controller);
|
||||
RefreshManagerBankwise(ControllerCore& controllerCore);
|
||||
virtual ~RefreshManagerBankwise();
|
||||
|
||||
virtual bool hasCollision(const CommandSchedule& schedule) override;
|
||||
virtual bool hasCollision(const ScheduledCommand& command) override;
|
||||
virtual bool hasCollision(const ScheduledCommand& command) override;
|
||||
virtual void scheduleRefresh(tlm::tlm_generic_payload& payload, sc_time time) override;
|
||||
|
||||
void reInitialize(Bank bank, sc_time time) override;
|
||||
@@ -33,7 +30,7 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
ControllerCore& controller;
|
||||
ControllerCore& controllerCore;
|
||||
|
||||
std::map<Bank, tlm::tlm_generic_payload> refreshPayloads;
|
||||
std::map<Bank, sc_time> nextPlannedRefreshs;
|
||||
@@ -41,6 +38,5 @@ private:
|
||||
void planNextRefresh(Bank bank);
|
||||
};
|
||||
|
||||
} /* namespace controller */
|
||||
|
||||
#endif /* BANKWISEREFRESHMANAGER_H_ */
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* CommandSchedule.h
|
||||
*
|
||||
* Created on: Mar 5, 2014
|
||||
* Author: jonny
|
||||
*/
|
||||
|
||||
#ifndef COMMANDSCHEDULE_H_
|
||||
#define COMMANDSCHEDULE_H_
|
||||
|
||||
#include <vector>
|
||||
#include "../../../common/dramExtension.h"
|
||||
#include "../../../common/TlmRecorder.h"
|
||||
#include "ScheduledCommand.h"
|
||||
namespace core {
|
||||
|
||||
class CommandSchedule
|
||||
{
|
||||
public:
|
||||
CommandSchedule(tlm::tlm_generic_payload& transaction) :
|
||||
extension(DramExtension::getExtension(&transaction))
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~CommandSchedule()
|
||||
{
|
||||
}
|
||||
|
||||
ScheduledCommand& add(Command command, sc_time start, sc_time executionTime)
|
||||
{
|
||||
scheduledCommands.push_back(ScheduledCommand(command, start, executionTime, extension));
|
||||
return scheduledCommands.back();
|
||||
}
|
||||
|
||||
const std::vector<ScheduledCommand>& getScheduledCommands() const
|
||||
{
|
||||
return scheduledCommands;
|
||||
}
|
||||
|
||||
sc_time getStart() const
|
||||
{
|
||||
return scheduledCommands.front().getStart();
|
||||
}
|
||||
|
||||
sc_time getEnd() const
|
||||
{
|
||||
return scheduledCommands.back().getEnd();
|
||||
}
|
||||
|
||||
sc_time getExecutionTime() const
|
||||
{
|
||||
return scheduledCommands.back().getEnd() - scheduledCommands.front().getStart();
|
||||
}
|
||||
|
||||
Bank getBank() const
|
||||
{
|
||||
return extension.getBank();
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<ScheduledCommand> scheduledCommands;
|
||||
DramExtension extension;
|
||||
};
|
||||
|
||||
} /* namespace controller */
|
||||
|
||||
#endif /* COMMANDSCHEDULE_H_ */
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* CommandSequenceGenerator.cpp
|
||||
*
|
||||
* Created on: Mar 5, 2014
|
||||
* Author: jonny
|
||||
*/
|
||||
|
||||
#include "CommandSequenceGenerator.h"
|
||||
#include "../../../common/dramExtension.h"
|
||||
#include "../configuration/Configuration.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace core {
|
||||
|
||||
CommandSequence CommandSequenceGenerator::generateCommandSequence(tlm::tlm_generic_payload& transaction)
|
||||
{
|
||||
const DramExtension& extension = DramExtension::getExtension(&transaction);
|
||||
Bank bank = extension.getBank();
|
||||
Row row = extension.getRow();
|
||||
|
||||
CommandSequence result;
|
||||
|
||||
if (!controllerState.rowBufferStates.rowBufferIsOpen(bank))
|
||||
{
|
||||
return getBankMissCommandSequence(transaction);
|
||||
}
|
||||
else if (controllerState.rowBufferStates.getRowInRowBuffer(bank) != row)
|
||||
{
|
||||
return getRowMissCommandSequence(transaction);
|
||||
}
|
||||
else
|
||||
{
|
||||
return getRowHitCommandSequence(transaction);
|
||||
}
|
||||
}
|
||||
|
||||
CommandSequence CommandSequenceGenerator::generateCommandSequence(
|
||||
tlm::tlm_generic_payload* transaction)
|
||||
{
|
||||
return generateCommandSequence(*transaction);
|
||||
}
|
||||
|
||||
CommandSequence CommandSequenceGenerator::getBankMissCommandSequence(tlm::tlm_generic_payload& transaction)
|
||||
{
|
||||
vector<Command> result;
|
||||
result.push_back(Command::Activate);
|
||||
result.push_back(getReadWriteCommand(transaction));
|
||||
return result;
|
||||
}
|
||||
|
||||
CommandSequence CommandSequenceGenerator::getRowMissCommandSequence(tlm::tlm_generic_payload& transaction)
|
||||
{
|
||||
vector<Command> result;
|
||||
result.push_back(Command::Precharge);
|
||||
result.push_back(Command::Activate);
|
||||
result.push_back(getReadWriteCommand(transaction));
|
||||
return result;
|
||||
}
|
||||
|
||||
CommandSequence CommandSequenceGenerator::getRowHitCommandSequence(tlm::tlm_generic_payload& transaction)
|
||||
{
|
||||
vector<Command> result;
|
||||
result.push_back(getReadWriteCommand(transaction));
|
||||
return result;
|
||||
}
|
||||
|
||||
Command CommandSequenceGenerator::getReadWriteCommand(tlm::tlm_generic_payload& transaction)
|
||||
{
|
||||
|
||||
if (transaction.get_command() == tlm::TLM_READ_COMMAND)
|
||||
{
|
||||
if(Configuration::getInstance().OpenPagePolicy)
|
||||
return Command::Read;
|
||||
else
|
||||
return Command::ReadA;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(Configuration::getInstance().OpenPagePolicy)
|
||||
return Command::Write;
|
||||
else
|
||||
return Command::WriteA;
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace controller */
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* CommandGenerator.h
|
||||
*
|
||||
* Created on: Mar 5, 2014
|
||||
* Author: jonny
|
||||
*/
|
||||
|
||||
#ifndef COMMANDGENERATOR_H_
|
||||
#define COMMANDGENERATOR_H_
|
||||
|
||||
#include <tlm.h>
|
||||
#include <vector>
|
||||
#include "../ControllerState.h"
|
||||
#include "../Command.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
class CommandSequenceGenerator {
|
||||
public:
|
||||
CommandSequenceGenerator(const ControllerState& controllerState) : controllerState(controllerState) {}
|
||||
virtual ~CommandSequenceGenerator() {}
|
||||
|
||||
CommandSequence generateCommandSequence(tlm::tlm_generic_payload& transaction);
|
||||
CommandSequence generateCommandSequence(tlm::tlm_generic_payload* transaction);
|
||||
|
||||
private:
|
||||
const ControllerState& controllerState;
|
||||
|
||||
Command getReadWriteCommand(tlm::tlm_generic_payload& transaction);
|
||||
CommandSequence getBankMissCommandSequence(tlm::tlm_generic_payload& transaction);
|
||||
CommandSequence getRowMissCommandSequence(tlm::tlm_generic_payload& transaction);
|
||||
CommandSequence getRowHitCommandSequence(tlm::tlm_generic_payload& transaction);
|
||||
};
|
||||
|
||||
} /* namespace controller */
|
||||
|
||||
#endif /* COMMANDGENERATOR_H_ */
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* CommandSequenceScheduler.cpp
|
||||
*
|
||||
* Created on: Mar 9, 2014
|
||||
* Author: jonny
|
||||
*/
|
||||
|
||||
#include "CommandSequenceScheduler.h"
|
||||
#include "../ControllerCore.h"
|
||||
#include "../../../common/DebugManager.h"
|
||||
#include "../TimingCalculation.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
CommandSchedule CommandSequenceScheduler::schedule(CommandSequence commands, sc_time start,
|
||||
tlm::tlm_generic_payload& transaction)
|
||||
{
|
||||
CommandSchedule schedule(transaction);
|
||||
|
||||
for (Command cmd : commands)
|
||||
{
|
||||
ControllerCore::printDebugMessage("Scheduling command " + commandToString(cmd));
|
||||
|
||||
ICommandChecker& checker = controller.getCommandChecker(cmd);
|
||||
|
||||
sc_time executionTime = getExecutionTime(cmd,transaction);
|
||||
ScheduledCommand& scheduledCommand = schedule.add(cmd, start, executionTime);
|
||||
checker.delayToSatisfyConstraints(scheduledCommand);
|
||||
|
||||
sc_assert(scheduledCommand.getStart()>=start && scheduledCommand.getStart() < scheduledCommand.getEnd());
|
||||
controller.state.change(scheduledCommand);
|
||||
}
|
||||
|
||||
return schedule;
|
||||
}
|
||||
|
||||
} /* namespace controller */
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* CommandSequenceScheduler.h
|
||||
*
|
||||
* Created on: Mar 9, 2014
|
||||
* Author: jonny
|
||||
*/
|
||||
|
||||
#ifndef COMMANDSEQUENCESCHEDULER_H_
|
||||
#define COMMANDSEQUENCESCHEDULER_H_
|
||||
|
||||
#include "CommandSchedule.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
class ControllerCore;
|
||||
|
||||
class CommandSequenceScheduler
|
||||
{
|
||||
public:
|
||||
CommandSequenceScheduler(ControllerCore& controller) : controller(controller){}
|
||||
virtual ~CommandSequenceScheduler(){}
|
||||
|
||||
CommandSchedule schedule(CommandSequence commands, sc_time start, tlm::tlm_generic_payload& transaction);
|
||||
|
||||
private:
|
||||
ControllerCore& controller;
|
||||
};
|
||||
|
||||
} /* namespace controller */
|
||||
|
||||
#endif /* COMMANDSEQUENCESCHEDULER_H_ */
|
||||
@@ -9,8 +9,6 @@
|
||||
#include "../../../common/Utils.h"
|
||||
#include "../configuration/Configuration.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
bool ScheduledCommand::isNoCommand() const
|
||||
{
|
||||
return (command == Command::NOP && start == SC_ZERO_TIME && executionTime == SC_ZERO_TIME && end == SC_ZERO_TIME);
|
||||
@@ -38,7 +36,9 @@ void ScheduledCommand::delayStart(sc_time delay)
|
||||
setStart(start+delay);
|
||||
}
|
||||
|
||||
void ScheduledCommand::delayToMeetConstraint(sc_time previous, sc_time constraint)
|
||||
// Delays the command so that its start is at least value(constraint) from timepoint previous apart.
|
||||
// If passed a constraint of 0ns, method will make sure that command starts no earlier than at timepoint previous
|
||||
void ScheduledCommand::establishMinDistanceFromStart(sc_time previous, sc_time constraint)
|
||||
{
|
||||
delayStart(getDelayToMeetConstraint(previous, start, constraint));
|
||||
}
|
||||
@@ -106,7 +106,3 @@ TimeInterval ScheduledCommand::getIntervalOnDataStrobe() const
|
||||
return TimeInterval(getStart() + timings.tWL - timings.clk / 2, getStart() + timings.tWL + getWriteAccessTime() - timings.clk / 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -10,12 +10,11 @@
|
||||
|
||||
#include <systemc.h>
|
||||
#include <tlm.h>
|
||||
#include "../Command.h"
|
||||
#include "../../Command.h"
|
||||
#include "../../../common/dramExtension.h"
|
||||
#include "../../../common/TlmRecorder.h"
|
||||
#include "../../../common/Utils.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
class ScheduledCommand
|
||||
{
|
||||
@@ -27,6 +26,11 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
ScheduledCommand(Command command, sc_time start, sc_time executionTime, const tlm::tlm_generic_payload& payload) :
|
||||
ScheduledCommand(command, start, executionTime, DramExtension::getExtension(payload))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ScheduledCommand() :
|
||||
command(Command::NOP), start(SC_ZERO_TIME), executionTime(SC_ZERO_TIME), end(SC_ZERO_TIME), extension()
|
||||
@@ -39,7 +43,7 @@ public:
|
||||
const sc_time getStart() const;
|
||||
void setStart(sc_time newStart);
|
||||
void delayStart(sc_time delay);
|
||||
void delayToMeetConstraint(sc_time previous, sc_time constraint);
|
||||
void establishMinDistanceFromStart(sc_time previous, sc_time constraint);
|
||||
|
||||
sc_time getEnd() const;
|
||||
Command getCommand() const;
|
||||
@@ -63,6 +67,5 @@ private:
|
||||
sc_time end;
|
||||
DramExtension extension;
|
||||
};
|
||||
} /* namespace controller */
|
||||
|
||||
#endif /* SCHEDULEDCOMMAND_H_ */
|
||||
|
||||
@@ -8,10 +8,8 @@
|
||||
#ifndef TRIGGER_H_
|
||||
#define TRIGGER_H_
|
||||
|
||||
namespace core {
|
||||
|
||||
enum Trigger {REFTrigger, PDNTrigger};
|
||||
|
||||
} /* namespace controller */
|
||||
|
||||
#endif /* TRIGGER_H_ */
|
||||
|
||||
@@ -10,12 +10,10 @@
|
||||
#include "ActivateChecker.h"
|
||||
#include "../../TimingCalculation.h"
|
||||
#include "../../../../common/DebugManager.h"
|
||||
#include "../../Command.h"
|
||||
#include "../../../Command.h"
|
||||
#include "../../../../common/Utils.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace core {
|
||||
|
||||
void ActivateChecker::delayToSatisfyConstraints(ScheduledCommand& command) const
|
||||
{
|
||||
sc_assert(command.getCommand() == Command::Activate);
|
||||
@@ -25,28 +23,28 @@ void ActivateChecker::delayToSatisfyConstraints(ScheduledCommand& command) const
|
||||
{
|
||||
if (lastCommandOnBank.getCommand() == Command::Precharge)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommandOnBank.getStart(), config.memSpec.tRP);
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), config.memSpec.tRP);
|
||||
}
|
||||
else if (lastCommandOnBank.getCommand() == Command::ReadA)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommandOnBank.getStart(), config.memSpec.tRTP + config.memSpec.tRP);
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), config.memSpec.tRTP + config.memSpec.tRP);
|
||||
}
|
||||
else if (lastCommandOnBank.getCommand() == Command::WriteA)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommandOnBank.getStart(),
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(),
|
||||
config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR + config.memSpec.tRP);
|
||||
}
|
||||
else if (lastCommandOnBank.getCommand() == Command::AutoRefresh)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommandOnBank.getStart(), config.memSpec.tRFC);
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), config.memSpec.tRFC);
|
||||
}
|
||||
else if (lastCommandOnBank.getCommand() == Command::PDNPX || lastCommandOnBank.getCommand() == Command::PDNAX)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommandOnBank.getStart(), config.memSpec.tXP);
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), config.memSpec.tXP);
|
||||
}
|
||||
else if (lastCommandOnBank.getCommand() == Command::SREFX)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommandOnBank.getStart(), config.memSpec.tXSR);
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), config.memSpec.tXSR);
|
||||
}
|
||||
else
|
||||
reportFatal("Activate Checker", "Activate can not follow " + commandToString(lastCommandOnBank.getCommand()));
|
||||
@@ -67,7 +65,7 @@ void ActivateChecker::delay_to_satisfy_activateToActivate_sameBank(ScheduledComm
|
||||
ScheduledCommand lastActivateOnBank = state.getLastCommand(Command::Activate, command.getBank());
|
||||
if (lastActivateOnBank.isValidCommand())
|
||||
{
|
||||
command.delayToMeetConstraint(lastActivateOnBank.getStart(), config.memSpec.tRC);
|
||||
command.establishMinDistanceFromStart(lastActivateOnBank.getStart(), config.memSpec.tRC);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,5 +109,3 @@ bool ActivateChecker::satisfies_nActivateWindow(ScheduledCommand& command) const
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} /* namespace controller */
|
||||
|
||||
@@ -11,9 +11,7 @@
|
||||
#include <map>
|
||||
#include "ICommandChecker.h"
|
||||
#include "../../configuration/Configuration.h"
|
||||
#include "../../ControllerState.h"
|
||||
|
||||
namespace core {
|
||||
#include "../../../ControllerState.h"
|
||||
|
||||
class ActivateChecker: public ICommandChecker
|
||||
{
|
||||
@@ -31,6 +29,4 @@ private:
|
||||
bool satisfies_nActivateWindow(ScheduledCommand& command) const;
|
||||
};
|
||||
|
||||
} /* namespace controller */
|
||||
|
||||
#endif /* ACTIVATESCHEDULER_H_ */
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include <systemc.h>
|
||||
#include "../ScheduledCommand.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
class ICommandChecker
|
||||
{
|
||||
@@ -20,7 +19,6 @@ public:
|
||||
virtual void delayToSatisfyConstraints(ScheduledCommand& command) const = 0;
|
||||
};
|
||||
|
||||
} /* namespace controller */
|
||||
|
||||
|
||||
#endif /* ICOMMANDSCHEDULER_H_ */
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include "PowerDownChecker.h"
|
||||
#include "../../TimingCalculation.h"
|
||||
|
||||
namespace core {
|
||||
void PowerDownChecker::delayToSatisfyConstraints(ScheduledCommand& command) const
|
||||
{
|
||||
sc_assert(
|
||||
@@ -23,31 +22,31 @@ void PowerDownChecker::delayToSatisfyConstraints(ScheduledCommand& command) cons
|
||||
{
|
||||
if (lastCommandOnBank.getCommand() == Command::Read || lastCommandOnBank.getCommand() == Command::ReadA)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommandOnBank.getStart(),
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(),
|
||||
config.memSpec.tRL + getReadAccessTime() + config.memSpec.clk);
|
||||
}
|
||||
else if (lastCommandOnBank.getCommand() == Command::Write)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommandOnBank.getStart(),
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(),
|
||||
config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR);
|
||||
}
|
||||
else if (lastCommandOnBank.getCommand() == Command::WriteA)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommandOnBank.getStart(),
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(),
|
||||
config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR + config.memSpec.clk);
|
||||
}
|
||||
else if (lastCommandOnBank.getCommand() == Command::AutoRefresh)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommandOnBank.getStart(), config.memSpec.tRFC);
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), config.memSpec.tRFC);
|
||||
}
|
||||
else if (lastCommandOnBank.getCommand() == Command::PDNPX || lastCommandOnBank.getCommand() == Command::PDNAX)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommandOnBank.getStart(), config.memSpec.tXP);
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), config.memSpec.tXP);
|
||||
}
|
||||
|
||||
else if (lastCommandOnBank.getCommand() == Command::SREFX)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommandOnBank.getStart(), config.memSpec.tXSR);
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), config.memSpec.tXSR);
|
||||
}
|
||||
|
||||
else
|
||||
@@ -59,19 +58,17 @@ void PowerDownChecker::delayToSatisfyConstraints(ScheduledCommand& command) cons
|
||||
|
||||
else if (command.getCommand() == Command::PDNAX)
|
||||
{
|
||||
command.delayToMeetConstraint(state.getLastCommand(Command::PDNA).getStart(), config.memSpec.tCKE);
|
||||
command.establishMinDistanceFromStart(state.getLastCommand(Command::PDNA).getStart(), config.memSpec.tCKE);
|
||||
}
|
||||
else if (command.getCommand() == Command::PDNPX)
|
||||
{
|
||||
command.delayToMeetConstraint(state.getLastCommand(Command::PDNP).getStart(), config.memSpec.tCKE);
|
||||
command.establishMinDistanceFromStart(state.getLastCommand(Command::PDNP).getStart(), config.memSpec.tCKE);
|
||||
}
|
||||
else if (command.getCommand() == Command::SREFX)
|
||||
{
|
||||
command.delayToMeetConstraint(state.getLastCommand(Command::SREF).getStart(), config.memSpec.tCKESR);
|
||||
command.establishMinDistanceFromStart(state.getLastCommand(Command::SREF).getStart(), config.memSpec.tCKESR);
|
||||
}
|
||||
|
||||
state.bus.moveCommandToNextFreeSlot(command);
|
||||
}
|
||||
|
||||
} /* namespace core */
|
||||
|
||||
|
||||
@@ -8,12 +8,11 @@
|
||||
#ifndef POWERDOWNCHECKER_H_
|
||||
#define POWERDOWNCHECKER_H_
|
||||
|
||||
#include "../../ControllerState.h"
|
||||
#include "../../../ControllerState.h"
|
||||
#include "../../configuration/Configuration.h"
|
||||
#include "ICommandChecker.h"
|
||||
#include <systemc>
|
||||
|
||||
namespace core {
|
||||
|
||||
class PowerDownChecker : public ICommandChecker
|
||||
{
|
||||
@@ -33,6 +32,5 @@ private:
|
||||
ControllerState& state;
|
||||
};
|
||||
|
||||
} /* namespace core */
|
||||
|
||||
#endif /* POWERDOWNCHECKER_H_ */
|
||||
|
||||
@@ -8,44 +8,52 @@
|
||||
#include "PrechargeAllChecker.h"
|
||||
#include "../../TimingCalculation.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
void PrechargeAllChecker::delayToSatisfyConstraints(ScheduledCommand& command) const
|
||||
{
|
||||
sc_assert(command.getCommand() == Command::PrechargeAll);
|
||||
|
||||
// Consider all banks for the constraints, since precharge all command is supposed to happen at the same time on all banks
|
||||
for (unsigned int bank = 0; bank < config.memSpec.NumberOfBanks; ++bank)
|
||||
{
|
||||
ScheduledCommand lastCommand = state.getLastScheduledCommand(Bank(bank));
|
||||
if (lastCommand.isValidCommand())
|
||||
{
|
||||
if (lastCommand.getCommand() == Command::Read)
|
||||
if(lastCommand.getCommand() == Command::Precharge)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommand.getStart(), config.memSpec.tRTP);
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tRP);
|
||||
}
|
||||
else if(lastCommand.getCommand() == Command::Activate)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tRCD);
|
||||
}
|
||||
else if (lastCommand.getCommand() == Command::Read)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tRTP);
|
||||
}
|
||||
else if (lastCommand.getCommand() == Command::ReadA)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommand.getStart(), config.memSpec.tRTP + config.memSpec.tRP);
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tRTP + config.memSpec.tRP);
|
||||
}
|
||||
else if (lastCommand.getCommand() == Command::Write)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommand.getStart(), config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR);
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR);
|
||||
}
|
||||
else if(lastCommand.getCommand() == Command::WriteA)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommand.getStart(), config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR + config.memSpec.tRP);
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR + config.memSpec.tRP);
|
||||
}
|
||||
else if (lastCommand.getCommand() == Command::AutoRefresh)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommand.getStart(), config.memSpec.tRFC);
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tRFC);
|
||||
}
|
||||
else if (lastCommand.getCommand() == Command::PDNAX || lastCommand.getCommand() == Command::PDNPX)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommand.getStart(), config.memSpec.tXP);
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tXP);
|
||||
}
|
||||
else if (lastCommand.getCommand() == Command::SREFX)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommand.getEnd(), config.memSpec.tXSR);
|
||||
command.establishMinDistanceFromStart(lastCommand.getEnd(), config.memSpec.tXSR);
|
||||
}
|
||||
else
|
||||
reportFatal("Precharge All Checker",
|
||||
@@ -56,10 +64,9 @@ void PrechargeAllChecker::delayToSatisfyConstraints(ScheduledCommand& command) c
|
||||
ScheduledCommand lastActivate = state.getLastCommand(Command::Activate, command.getBank());
|
||||
if (lastActivate.isValidCommand())
|
||||
{
|
||||
command.delayToMeetConstraint(lastActivate.getStart(), config.memSpec.tRAS);
|
||||
command.establishMinDistanceFromStart(lastActivate.getStart(), config.memSpec.tRAS);
|
||||
}
|
||||
|
||||
state.bus.moveCommandToNextFreeSlot(command);
|
||||
}
|
||||
|
||||
} /* namespace core */
|
||||
|
||||
@@ -10,11 +10,10 @@
|
||||
|
||||
#include "ICommandChecker.h"
|
||||
#include "../../configuration/Configuration.h"
|
||||
#include "../../ControllerState.h"
|
||||
#include "../../../ControllerState.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
class PrechargeAllChecker: public core::ICommandChecker
|
||||
class PrechargeAllChecker: public ICommandChecker
|
||||
{
|
||||
public:
|
||||
PrechargeAllChecker(const Configuration& config, ControllerState& state) :
|
||||
@@ -32,6 +31,5 @@ private:
|
||||
ControllerState& state;
|
||||
};
|
||||
|
||||
} /* namespace core */
|
||||
|
||||
#endif /* PRECHARGEALLCHECKER_H_ */
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include "PrechargeChecker.h"
|
||||
#include "../../TimingCalculation.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
void PrechargeChecker::delayToSatisfyConstraints(ScheduledCommand& command) const
|
||||
{
|
||||
@@ -19,18 +18,29 @@ void PrechargeChecker::delayToSatisfyConstraints(ScheduledCommand& command) cons
|
||||
|
||||
if (lastCommand.isValidCommand())
|
||||
{
|
||||
if (lastCommand.getCommand() == Command::Read)
|
||||
// the first two cases happen when a resfresh interrups the command sequence of a transaction
|
||||
// (e.g. commands to process transaction are PRE-ACT-RD and refresh happens after the PRE or after the ACT)
|
||||
if(lastCommand.getCommand() == Command::Precharge)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommand.getStart(),config.memSpec.tRTP);
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tRP);
|
||||
}
|
||||
else if(lastCommand.getCommand() == Command::Activate)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tRCD);
|
||||
}
|
||||
|
||||
else if (lastCommand.getCommand() == Command::Read)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(),config.memSpec.tRTP);
|
||||
}
|
||||
else if (lastCommand.getCommand() == Command::Write)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommand.getStart(), config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR);
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR);
|
||||
|
||||
}
|
||||
else if (lastCommand.getCommand() == Command::PDNAX)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommand.getStart(), config.memSpec.tXP);
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tXP);
|
||||
}
|
||||
else
|
||||
reportFatal("Precharge Checker", "Precharge can not follow " + commandToString(lastCommand.getCommand()));
|
||||
@@ -39,11 +49,9 @@ void PrechargeChecker::delayToSatisfyConstraints(ScheduledCommand& command) cons
|
||||
ScheduledCommand lastActivate = state.getLastCommand(Command::Activate, command.getBank());
|
||||
if (lastActivate.isValidCommand())
|
||||
{
|
||||
command.delayToMeetConstraint(lastActivate.getStart(), config.memSpec.tRAS);
|
||||
command.establishMinDistanceFromStart(lastActivate.getStart(), config.memSpec.tRAS);
|
||||
}
|
||||
|
||||
|
||||
state.bus.moveCommandToNextFreeSlot(command);
|
||||
}
|
||||
|
||||
} /* namespace controller */
|
||||
|
||||
@@ -10,11 +10,10 @@
|
||||
|
||||
#include "ICommandChecker.h"
|
||||
#include "../../configuration/Configuration.h"
|
||||
#include "../../ControllerState.h"
|
||||
#include "../../../ControllerState.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
class PrechargeChecker: public core::ICommandChecker
|
||||
class PrechargeChecker: public ICommandChecker
|
||||
{
|
||||
public:
|
||||
PrechargeChecker(const Configuration& config, ControllerState& state) : config(config), state(state) {}
|
||||
@@ -26,6 +25,5 @@ private:
|
||||
ControllerState& state;
|
||||
};
|
||||
|
||||
} /* namespace controller */
|
||||
|
||||
#endif /* PRECHARGECHECKER_H_ */
|
||||
|
||||
@@ -10,49 +10,29 @@
|
||||
#include "../../../../common/Utils.h"
|
||||
#include "WriteChecker.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
void ReadChecker::delayToSatisfyConstraints(ScheduledCommand& command) const
|
||||
{
|
||||
sc_assert(command.getCommand() == Command::Read || command.getCommand() == Command::ReadA);
|
||||
|
||||
delayToSatisfyDLL(command);
|
||||
|
||||
ScheduledCommand lastCommand = state.getLastScheduledCommand(command.getBank());
|
||||
|
||||
//fifo patch
|
||||
if(config.Scheduler == "FIFO")
|
||||
{
|
||||
|
||||
//no access can accelerate other access
|
||||
ScheduledCommand lastread = state.getLastCommand(Command::Read);
|
||||
ScheduledCommand lastwrite = state.getLastCommand(Command::Write);
|
||||
ScheduledCommand lastreada = state.getLastCommand(Command::ReadA);
|
||||
ScheduledCommand lastwritea = state.getLastCommand(Command::WriteA);
|
||||
|
||||
command.delayToMeetConstraint(lastread.getStart(), SC_ZERO_TIME);
|
||||
command.delayToMeetConstraint(lastreada.getStart(), SC_ZERO_TIME);
|
||||
command.delayToMeetConstraint(lastwrite.getStart(), SC_ZERO_TIME);
|
||||
command.delayToMeetConstraint(lastwritea.getStart(), SC_ZERO_TIME);
|
||||
}
|
||||
|
||||
if (lastCommand.isValidCommand())
|
||||
{
|
||||
if (lastCommand.getCommand() == Command::Activate)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommand.getStart(), config.memSpec.tRCD);
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tRCD);
|
||||
}
|
||||
else if (lastCommand.getCommand() == Command::Read)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommand.getStart(), ReadChecker::readToRead(lastCommand,command));
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), ReadChecker::readToRead(lastCommand,command));
|
||||
}
|
||||
else if (lastCommand.getCommand() == Command::Write)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommand.getStart(), ReadChecker::writeToRead(lastCommand, command));
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), ReadChecker::writeToRead(lastCommand, command));
|
||||
}
|
||||
else if (lastCommand.getCommand() == Command::PDNPX || lastCommand.getCommand() == Command::PDNAX)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommand.getStart(), config.memSpec.tXP);
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tXP);
|
||||
}
|
||||
else
|
||||
reportFatal("Read Checker", "Read can not follow " + commandToString(lastCommand.getCommand()));
|
||||
@@ -100,7 +80,7 @@ void ReadChecker::delayToSatisfyDLL(ScheduledCommand& read) const
|
||||
{
|
||||
ScheduledCommand lastSREFX = state.getLastCommand(Command::SREFX, read.getBank());
|
||||
if (lastSREFX.isValidCommand())
|
||||
read.delayToMeetConstraint(lastSREFX.getStart(), config.memSpec.tXSRDLL);
|
||||
read.establishMinDistanceFromStart(lastSREFX.getStart(), config.memSpec.tXSRDLL);
|
||||
}
|
||||
|
||||
sc_time ReadChecker::readToRead(ScheduledCommand& firstRead, ScheduledCommand& secondRead)
|
||||
@@ -123,5 +103,4 @@ sc_time ReadChecker::writeToRead(ScheduledCommand& write, ScheduledCommand& read
|
||||
return config.tWL + getWriteAccessTime() + tWTR;
|
||||
}
|
||||
|
||||
} /* namespace controller */
|
||||
|
||||
|
||||
@@ -10,11 +10,10 @@
|
||||
|
||||
#include "ICommandChecker.h"
|
||||
#include "../../configuration/Configuration.h"
|
||||
#include "../../ControllerState.h"
|
||||
#include "../../../ControllerState.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
class ReadChecker: public core::ICommandChecker
|
||||
class ReadChecker: public ICommandChecker
|
||||
{
|
||||
public:
|
||||
ReadChecker(Configuration& config, ControllerState& state) : config(config), state(state) {}
|
||||
@@ -34,6 +33,5 @@ private:
|
||||
bool collidesWithStrobeCommand(ScheduledCommand& read, ScheduledCommand& strobeCommand) const;
|
||||
};
|
||||
|
||||
} /* namespace controller */
|
||||
|
||||
#endif /* READCHECKER_H_ */
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "../../TimingCalculation.h"
|
||||
|
||||
|
||||
namespace core {
|
||||
|
||||
void RefreshChecker::delayToSatisfyConstraints(ScheduledCommand& command) const
|
||||
{
|
||||
@@ -21,24 +20,24 @@ void RefreshChecker::delayToSatisfyConstraints(ScheduledCommand& command) const
|
||||
{
|
||||
if (lastCommandOnBank.getCommand() == Command::Precharge || lastCommandOnBank.getCommand() == Command::PrechargeAll)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommandOnBank.getStart(), config.memSpec.tRP);
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), config.memSpec.tRP);
|
||||
}
|
||||
else if (lastCommandOnBank.getCommand() == Command::ReadA)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommandOnBank.getStart(), config.memSpec.tRTP + config.memSpec.tRP);
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), config.memSpec.tRTP + config.memSpec.tRP);
|
||||
}
|
||||
else if (lastCommandOnBank.getCommand() == Command::WriteA)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommandOnBank.getStart(),
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(),
|
||||
config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR + config.memSpec.tRP);
|
||||
}
|
||||
else if (lastCommandOnBank.getCommand() == Command::PDNPX || lastCommandOnBank.getCommand() == Command::PDNAX)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommandOnBank.getStart(), config.memSpec.tXP);
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), config.memSpec.tXP);
|
||||
}
|
||||
else if (lastCommandOnBank.getCommand() == Command::SREFX)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommandOnBank.getStart(), config.memSpec.tXSR);
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), config.memSpec.tXSR);
|
||||
}
|
||||
else if (lastCommandOnBank.getCommand() == Command::AutoRefresh)
|
||||
{
|
||||
@@ -50,5 +49,4 @@ void RefreshChecker::delayToSatisfyConstraints(ScheduledCommand& command) const
|
||||
state.bus.moveCommandToNextFreeSlot(command);
|
||||
}
|
||||
|
||||
} /* namespace core */
|
||||
|
||||
|
||||
@@ -9,11 +9,10 @@
|
||||
#define REFRESHCHECKER_H_
|
||||
|
||||
#include "ICommandChecker.h"
|
||||
#include "../../ControllerState.h"
|
||||
#include "../../../ControllerState.h"
|
||||
#include "../../configuration/Configuration.h"
|
||||
#include <systemc>
|
||||
|
||||
namespace core {
|
||||
|
||||
class RefreshChecker: public ICommandChecker
|
||||
{
|
||||
@@ -34,6 +33,5 @@ private:
|
||||
|
||||
};
|
||||
|
||||
} /* namespace core */
|
||||
|
||||
#endif /* REFRESHCHECKER_H_ */
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "../../../../common/Utils.h"
|
||||
#include "ReadChecker.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
void WriteChecker::delayToSatisfyConstraints(ScheduledCommand& command) const
|
||||
{
|
||||
@@ -18,39 +17,23 @@ void WriteChecker::delayToSatisfyConstraints(ScheduledCommand& command) const
|
||||
|
||||
ScheduledCommand lastCommand = state.getLastScheduledCommand(command.getBank());
|
||||
|
||||
//fifo patch
|
||||
if(config.Scheduler == "FIFO")
|
||||
{
|
||||
|
||||
//no access can accelerate other access
|
||||
ScheduledCommand lastread = state.getLastCommand(Command::Read);
|
||||
ScheduledCommand lastwrite = state.getLastCommand(Command::Write);
|
||||
ScheduledCommand lastreada = state.getLastCommand(Command::ReadA);
|
||||
ScheduledCommand lastwritea = state.getLastCommand(Command::WriteA);
|
||||
|
||||
command.delayToMeetConstraint(lastread.getStart(), SC_ZERO_TIME);
|
||||
command.delayToMeetConstraint(lastreada.getStart(), SC_ZERO_TIME);
|
||||
command.delayToMeetConstraint(lastwrite.getStart(), SC_ZERO_TIME);
|
||||
command.delayToMeetConstraint(lastwritea.getStart(), SC_ZERO_TIME);
|
||||
}
|
||||
|
||||
if (lastCommand.isValidCommand())
|
||||
{
|
||||
if (lastCommand.getCommand() == Command::Activate)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommand.getStart(), config.memSpec.tRCD);
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tRCD);
|
||||
}
|
||||
else if (lastCommand.getCommand() == Command::Read)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommand.getStart(), WriteChecker::readToWrite(lastCommand, command));
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), WriteChecker::readToWrite(lastCommand, command));
|
||||
}
|
||||
else if (lastCommand.getCommand() == Command::Write)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommand.getStart(), WriteChecker::writeToWrite(lastCommand, command));
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), WriteChecker::writeToWrite(lastCommand, command));
|
||||
}
|
||||
else if (lastCommand.getCommand() == Command::PDNPX || lastCommand.getCommand() == Command::PDNAX)
|
||||
{
|
||||
command.delayToMeetConstraint(lastCommand.getStart(), config.memSpec.tXP);
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tXP);
|
||||
}
|
||||
else
|
||||
reportFatal("Write Checker", "Write can not follow " + commandToString(lastCommand.getCommand()));
|
||||
@@ -113,4 +96,3 @@ sc_time WriteChecker::readToWrite(ScheduledCommand& read, ScheduledCommand& writ
|
||||
return config.tRL + getReadAccessTime() - config.tWL + config.clk * 2;
|
||||
}
|
||||
|
||||
} /* namespace controller */
|
||||
|
||||
@@ -10,11 +10,10 @@
|
||||
|
||||
#include "ICommandChecker.h"
|
||||
#include "../../configuration/Configuration.h"
|
||||
#include "../../ControllerState.h"
|
||||
#include "../../../ControllerState.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
class WriteChecker: public core::ICommandChecker
|
||||
class WriteChecker: public ICommandChecker
|
||||
{
|
||||
public:
|
||||
WriteChecker(const Configuration& config, ControllerState& state) : config(config), state(state) {}
|
||||
@@ -31,6 +30,5 @@ private:
|
||||
ControllerState& state;
|
||||
};
|
||||
|
||||
} /* namespace controller */
|
||||
|
||||
#endif /* WRITECHECKER_H_ */
|
||||
|
||||
@@ -7,43 +7,28 @@
|
||||
|
||||
#include "Fifo.h"
|
||||
|
||||
|
||||
namespace scheduler {
|
||||
|
||||
bool Fifo::hasPayloads()
|
||||
{
|
||||
return getNumberOfQueuedPayloads() > 0;
|
||||
}
|
||||
using namespace std;
|
||||
|
||||
void Fifo::schedule(gp* payload)
|
||||
{
|
||||
buffer.push_back(payload);
|
||||
buffer[DramExtension::getExtension(payload).getBank()].emplace_back(payload);
|
||||
}
|
||||
|
||||
gp* Fifo::getNextPayload()
|
||||
pair<Command, tlm::tlm_generic_payload*> Fifo::getNextRequest(Bank bank)
|
||||
{
|
||||
if(!buffer.empty())
|
||||
if(!buffer[bank].empty())
|
||||
{
|
||||
DramExtension& frontRequest = DramExtension::getExtension(buffer.front());
|
||||
vector<Bank> freeBanks = controllerCore.getFreeBanks();
|
||||
if(std::find(freeBanks.begin(),freeBanks.end(),frontRequest.getBank()) != freeBanks.end())
|
||||
gp* payload = buffer[bank].front();
|
||||
Command command = IScheduler::getNextCommand(*payload);
|
||||
if(command == Command::Read || command == Command::ReadA || command == Command::Write || command == Command::WriteA)
|
||||
{
|
||||
return buffer.front();
|
||||
buffer[bank].pop_front();
|
||||
}
|
||||
|
||||
return pair<Command, tlm::tlm_generic_payload*>(command, payload);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return pair<Command, tlm::tlm_generic_payload*>(Command::NOP, NULL);
|
||||
}
|
||||
|
||||
void Fifo::removePayload(gp* /*payload*/)
|
||||
{
|
||||
buffer.pop_front();
|
||||
}
|
||||
|
||||
unsigned int Fifo::getNumberOfQueuedPayloads()
|
||||
{
|
||||
return buffer.size();
|
||||
}
|
||||
|
||||
} /* namespace scheduler */
|
||||
|
||||
|
||||
@@ -8,33 +8,26 @@
|
||||
#ifndef FIFO_H_
|
||||
#define FIFO_H_
|
||||
|
||||
#include "Scheduler.h"
|
||||
#include "../core/ControllerCore.h"
|
||||
#include "../Command.h"
|
||||
#include "IScheduler.h"
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
|
||||
|
||||
namespace scheduler {
|
||||
|
||||
class Fifo : public Scheduler
|
||||
class Fifo : public IScheduler
|
||||
{
|
||||
public:
|
||||
Fifo(core::ControllerCore &controllerCore) : controllerCore(controllerCore)
|
||||
Fifo(ControllerCore &controllerCore) : IScheduler(controllerCore)
|
||||
{}
|
||||
virtual ~Fifo()
|
||||
{}
|
||||
|
||||
virtual bool hasPayloads() override;
|
||||
virtual void schedule(gp* payload) override;
|
||||
virtual gp* getNextPayload() override;
|
||||
virtual void removePayload(gp* payload) override;
|
||||
void schedule(gp* payload) override;
|
||||
std::pair<Command, tlm::tlm_generic_payload*> getNextRequest(Bank bank) override;
|
||||
|
||||
private:
|
||||
std::deque<gp*> buffer;
|
||||
core::ControllerCore &controllerCore;
|
||||
unsigned int getNumberOfQueuedPayloads();
|
||||
std::map<Bank, std::deque<gp*>> buffer;
|
||||
};
|
||||
|
||||
} /* namespace scheduler */
|
||||
|
||||
#endif /* FIFO_H_ */
|
||||
|
||||
89
dram/src/controller/scheduler/FifoStrict.cpp
Normal file
89
dram/src/controller/scheduler/FifoStrict.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
#include "FifoStrict.h"
|
||||
|
||||
void FifoStrict::schedule(gp *payload)
|
||||
{
|
||||
buffer.push_back(payload);
|
||||
printDebugMessage("New payload scheduled. Total number " + std::to_string(buffer.size()) + "\n");
|
||||
}
|
||||
|
||||
void FifoStrict::printFrontElementState()
|
||||
{
|
||||
if(buffer.size() > 0)
|
||||
{
|
||||
printDebugMessage("Front element state - Bank: " + DramExtension::getBank(buffer.front()).toString() + " Operation: " +
|
||||
commandToString(getNextCommand(*buffer.front())) + "\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printDebugMessage("No fron element. Buffer is empty \n ");
|
||||
}
|
||||
}
|
||||
|
||||
void FifoStrict::NotifyBeginRD()
|
||||
{
|
||||
Bank oldFrontElementBank = DramExtension::getBank(buffer.front());
|
||||
buffer.erase(buffer.begin());
|
||||
printDebugMessage("Front element finished. New front Element: ");
|
||||
printFrontElementState();
|
||||
|
||||
if(buffer.size() > 0)
|
||||
{
|
||||
// If the new front element was orginally blocked, because it had to wait on the preceeding fron element, we have to unblock it.
|
||||
// We only have to unblock if the new fron element is waiting for a RD/WR operation
|
||||
if(commandIsIn(getNextCommand(*buffer.front()), {Command::Read, Command::Write, Command::ReadA, Command::WriteA})
|
||||
&& !controllerCore.bankIsBusy(DramExtension::getBank(buffer.front())))
|
||||
{
|
||||
printDebugMessage("Unblocking front element.\n");
|
||||
controller.scheduleNextFromScheduler(DramExtension::getBank(buffer.front()));
|
||||
}
|
||||
// If the new front element is on the same bank as the old one, we have let it make progress, even when the next command is not a RD/WR
|
||||
// because we are not calling scheduleNextFromScheduler from the calling side
|
||||
else if(oldFrontElementBank == DramExtension::getBank(*buffer.front()))
|
||||
{
|
||||
controller.scheduleNextFromScheduler(DramExtension::getBank(buffer.front()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::pair<Command, tlm::tlm_generic_payload *> FifoStrict::getNextRequest(Bank bank)
|
||||
{
|
||||
if(buffer.empty())
|
||||
{
|
||||
return pair<Command, tlm::tlm_generic_payload*>(Command::NOP, NULL);
|
||||
}
|
||||
|
||||
else if(DramExtension::getBank(buffer.front()) == bank)
|
||||
{
|
||||
Command command = getNextCommand(*buffer.front());
|
||||
pair<Command, tlm::tlm_generic_payload*> result(command, buffer.front());
|
||||
printDebugMessage("Operation for front Element scheduled. ");
|
||||
printFrontElementState();
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(unsigned int i = 1; i < buffer.size(); ++i)
|
||||
{
|
||||
if(DramExtension::getBank(buffer[i]) == bank)
|
||||
{
|
||||
Command command = getNextCommand(*buffer[i]);
|
||||
|
||||
// RD/WR operations have to be strictly in order across banks, so only allow progress on commands
|
||||
// other than RD/WR commands.
|
||||
if(commandIsIn(command, {Command::Read, Command::Write, Command::ReadA, Command::WriteA}))
|
||||
{
|
||||
printDebugMessage("Current queue element " + std::to_string(i) + " blocked. Waiting for earlier rd/wr to finish\n");
|
||||
return pair<Command, tlm::tlm_generic_payload*>(Command::NOP, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
return pair<Command, tlm::tlm_generic_payload*>(command, buffer[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pair<Command, tlm::tlm_generic_payload*>(Command::NOP, NULL);
|
||||
}
|
||||
}
|
||||
32
dram/src/controller/scheduler/FifoStrict.h
Normal file
32
dram/src/controller/scheduler/FifoStrict.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef FIFOSTRICT_H
|
||||
#define FIFOSTRICT_H
|
||||
|
||||
#include "../core/ControllerCore.h"
|
||||
#include "../Command.h"
|
||||
#include "../../common/dramExtension.h"
|
||||
#include "IScheduler.h"
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
|
||||
class FifoStrict : public IScheduler
|
||||
{
|
||||
public:
|
||||
FifoStrict(IController &controller,ControllerCore &controllerCore) :
|
||||
IScheduler(controllerCore), controller(controller)
|
||||
{}
|
||||
virtual ~FifoStrict()
|
||||
{}
|
||||
|
||||
void schedule(gp* payload) override;
|
||||
std::pair<Command, tlm::tlm_generic_payload*> getNextRequest(Bank bank) override;
|
||||
void NotifyBeginRD();
|
||||
|
||||
private:
|
||||
std::vector<gp*> buffer;
|
||||
IController &controller;
|
||||
void printFrontElementState();
|
||||
};
|
||||
|
||||
|
||||
#endif // FIFOSTRICT_H
|
||||
@@ -4,133 +4,47 @@
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
using namespace core;
|
||||
|
||||
namespace scheduler {
|
||||
|
||||
FR_FCFS::FR_FCFS(core::ControllerCore& controllerCore, bool useExternalStates, bool adaptiveOpenPage) :
|
||||
controllerCore(controllerCore), useExternalStates(useExternalStates), adaptiveOpenPage(
|
||||
adaptiveOpenPage)
|
||||
{
|
||||
}
|
||||
|
||||
FR_FCFS::~FR_FCFS()
|
||||
{
|
||||
}
|
||||
|
||||
bool FR_FCFS::hasPayloads()
|
||||
{
|
||||
return getNumberOfQueuedPayloads() > 0;
|
||||
}
|
||||
|
||||
|
||||
void FR_FCFS::schedule(gp* payload)
|
||||
|
||||
void FR_FCFS::schedule(gp *payload)
|
||||
{
|
||||
buffer[DramExtension::getExtension(payload).getBank()].emplace_back(payload);
|
||||
}
|
||||
|
||||
|
||||
void FR_FCFS::schedule(std::vector<gp*> payloads)
|
||||
{
|
||||
for(gp* payload: payloads)
|
||||
schedule(payload);
|
||||
}
|
||||
|
||||
gp* FR_FCFS::getNextPayload()
|
||||
{
|
||||
for(Bank bank: controllerCore.getFreeBanks())
|
||||
{
|
||||
if(!buffer[bank].empty())
|
||||
{
|
||||
Row openRowOnBank = (useExternalStates) ? controllerCore.getRowBufferStates().getRowInRowBuffer(bank) : internalBankstates.getRowInRowBuffer(bank);
|
||||
auto rowHits = findRowHits(bank, openRowOnBank);
|
||||
gp* result = rowHits.empty() ? buffer[bank].front() : rowHits.front();
|
||||
|
||||
if (!adaptiveOpenPage)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
rowHits = findRowHits(bank, DramExtension::getExtension(result).getRow());
|
||||
//other row hits are still in buffer, leave page open
|
||||
if (rowHits.size() > 1)
|
||||
Configuration::getInstance().OpenPagePolicy = true;
|
||||
else
|
||||
Configuration::getInstance().OpenPagePolicy = false;
|
||||
|
||||
//other row hits are still in buffer, leave page open
|
||||
if(findRowHits(bank,DramExtension::getExtension(result).getRow()).size() > 1)
|
||||
Configuration::getInstance().OpenPagePolicy = true;
|
||||
else
|
||||
Configuration::getInstance().OpenPagePolicy = false;
|
||||
|
||||
//no other hit in buffer, but row miss is waiting
|
||||
if(findRowHits(bank,DramExtension::getExtension(result).getRow()).size() == 1 && buffer[bank].size() > 2 )
|
||||
Configuration::getInstance().OpenPagePolicy = false;
|
||||
else
|
||||
Configuration::getInstance().OpenPagePolicy = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gp* FR_FCFS::popOldest(Bank bank)
|
||||
std::pair<Command, gp*> FR_FCFS::getNextRequest(Bank bank)
|
||||
{
|
||||
if(buffer[bank].empty())
|
||||
return NULL;
|
||||
gp* result = buffer[bank].front();
|
||||
buffer[bank].pop_front();
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned int FR_FCFS::getNumberOfQueuedPayloads()
|
||||
{
|
||||
unsigned int numberOfQueuedPaylods = 0;
|
||||
for(auto& bufferElement : buffer)
|
||||
{
|
||||
numberOfQueuedPaylods += bufferElement.second.size();
|
||||
return pair<Command, tlm::tlm_generic_payload*>(Command::NOP, NULL);
|
||||
}
|
||||
return numberOfQueuedPaylods;
|
||||
}
|
||||
|
||||
bool FR_FCFS::containsPayloadTragetingSameAddress(gp *payload)
|
||||
{
|
||||
Bank bank = DramExtension::getExtension(payload).getBank();
|
||||
Row row = DramExtension::getExtension(payload).getRow();
|
||||
|
||||
for(gp* bufferedPayload: buffer[bank])
|
||||
deque<gp*>::iterator it = FindRowHit(bank);
|
||||
if(it != buffer[bank].end())
|
||||
{
|
||||
if(DramExtension::getExtension(bufferedPayload).getRow() == row)
|
||||
return true;
|
||||
gp* payload = *it;
|
||||
buffer[bank].erase(it);
|
||||
return pair<Command, gp*>(getReadWriteCommand(*payload), payload);
|
||||
}
|
||||
return false;
|
||||
|
||||
return pair<Command, gp*>(getNextCommand(buffer[bank].front()), buffer[bank].front());
|
||||
}
|
||||
|
||||
std::vector<gp*> FR_FCFS::findRowHits(Bank bank, Row row)
|
||||
deque<gp*>::iterator FR_FCFS::FindRowHit(Bank bank)
|
||||
{
|
||||
vector<gp*> found;
|
||||
for (gp* payload : buffer[bank])
|
||||
deque<gp*> &queue = buffer[bank];
|
||||
|
||||
if(!controllerCore.getRowBufferStates().rowBufferIsOpen(bank))
|
||||
return queue.end();
|
||||
|
||||
for(auto it = queue.begin(); it!=queue.end(); it++)
|
||||
{
|
||||
if (DramExtension::getExtension(payload).getRow() == row)
|
||||
found.push_back(payload);
|
||||
gp* payload = *it;
|
||||
//Found row-hit
|
||||
if(DramExtension::getRow(payload) == controllerCore.getRowBufferStates().getRowInRowBuffer(bank))
|
||||
{
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
return queue.end();
|
||||
}
|
||||
|
||||
void FR_FCFS::removePayload(gp* payload)
|
||||
{
|
||||
Bank bank = DramExtension::getExtension(payload).getBank();
|
||||
buffer[bank].remove(payload);
|
||||
|
||||
if (!useExternalStates)
|
||||
{
|
||||
internalBankstates.openRowInRowBuffer(bank, DramExtension::getExtension(payload).getRow());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,41 +1,27 @@
|
||||
#ifndef FR_FCFS_H_
|
||||
#define FR_FCFS_H_
|
||||
|
||||
#include "Scheduler.h"
|
||||
#include "IScheduler.h"
|
||||
#include "../core/ControllerCore.h"
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace scheduler {
|
||||
|
||||
class FR_FCFS : public Scheduler
|
||||
class FR_FCFS : public IScheduler
|
||||
{
|
||||
public:
|
||||
FR_FCFS(core::ControllerCore& controllerCore, bool refreshAware, bool adaptiveOpenPage);
|
||||
virtual ~FR_FCFS();
|
||||
FR_FCFS(ControllerCore &controllerCore) : IScheduler(controllerCore){}
|
||||
virtual ~FR_FCFS(){}
|
||||
|
||||
virtual bool hasPayloads() override;
|
||||
virtual void schedule(gp* payload) override;
|
||||
virtual gp* getNextPayload() override;
|
||||
virtual void removePayload(gp* payload) override;
|
||||
void schedule(gp* payload) override;
|
||||
std::pair<Command, tlm::tlm_generic_payload*> getNextRequest(Bank bank) override;
|
||||
|
||||
//used by PAR_BS
|
||||
void schedule(std::vector<gp*> payloads);
|
||||
gp* popOldest(Bank bank);
|
||||
unsigned int getNumberOfQueuedPayloads();
|
||||
|
||||
//used by read/write grouper
|
||||
bool containsPayloadTragetingSameAddress(gp* payload);
|
||||
private:
|
||||
std::vector<gp*> findRowHits(Bank bank, Row row);
|
||||
std::map<Bank,std::list<gp*>> buffer;
|
||||
core::ControllerCore& controllerCore;
|
||||
core::RowBufferState internalBankstates;
|
||||
bool useExternalStates;
|
||||
bool adaptiveOpenPage;
|
||||
std::map<Bank, std::deque<gp*>> buffer;
|
||||
std::deque<gp*>::iterator FindRowHit(Bank bank);
|
||||
|
||||
};
|
||||
|
||||
} /* namespace scheduler */
|
||||
|
||||
#endif
|
||||
|
||||
58
dram/src/controller/scheduler/IScheduler.cpp
Normal file
58
dram/src/controller/scheduler/IScheduler.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
#include "IScheduler.h"
|
||||
#include "../../common/DebugManager.h"
|
||||
#include "../core/configuration/Configuration.h"
|
||||
|
||||
std::string IScheduler::sendername = "scheduler";
|
||||
|
||||
void IScheduler::printDebugMessage(std::string message)
|
||||
{
|
||||
DebugManager::getInstance().printDebugMessage(IScheduler::sendername, message);
|
||||
}
|
||||
|
||||
// Get the next command that is necessary to process the request representend by the payload
|
||||
Command IScheduler::getNextCommand(gp& payload)
|
||||
{
|
||||
Bank bank = DramExtension::getBank(payload);
|
||||
if(!controllerCore.getRowBufferStates().rowBufferIsOpen(bank))
|
||||
{
|
||||
return Command::Activate;
|
||||
}
|
||||
else if(controllerCore.getRowBufferStates().rowBufferIsOpen(bank) &&
|
||||
controllerCore.getRowBufferStates().getRowInRowBuffer(bank) != DramExtension::getRow(payload))
|
||||
{
|
||||
return Command::Precharge;
|
||||
}
|
||||
else
|
||||
{
|
||||
return getReadWriteCommand(payload);
|
||||
}
|
||||
}
|
||||
|
||||
Command IScheduler::getNextCommand(gp *payload)
|
||||
{
|
||||
return getNextCommand(*payload);
|
||||
}
|
||||
|
||||
Command IScheduler::getReadWriteCommand(gp& payload)
|
||||
{
|
||||
|
||||
if (payload.get_command() == tlm::TLM_READ_COMMAND)
|
||||
{
|
||||
if(Configuration::getInstance().OpenPagePolicy)
|
||||
return Command::Read;
|
||||
else
|
||||
return Command::ReadA;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(Configuration::getInstance().OpenPagePolicy)
|
||||
return Command::Write;
|
||||
else
|
||||
return Command::WriteA;
|
||||
}
|
||||
}
|
||||
|
||||
Command IScheduler::getReadWriteCommand(gp *payload)
|
||||
{
|
||||
return getReadWriteCommand(*payload);
|
||||
}
|
||||
33
dram/src/controller/scheduler/IScheduler.h
Normal file
33
dram/src/controller/scheduler/IScheduler.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef ISCHEDULER_H
|
||||
#define ISCHEDULER_H
|
||||
|
||||
|
||||
#include <tlm.h>
|
||||
#include "../../common/dramExtension.h"
|
||||
#include "../Command.h"
|
||||
#include "../core/ControllerCore.h"
|
||||
|
||||
typedef tlm::tlm_generic_payload gp;
|
||||
|
||||
class IScheduler
|
||||
{
|
||||
public:
|
||||
virtual ~IScheduler(){}
|
||||
IScheduler(ControllerCore &controllerCore) : controllerCore(controllerCore){}
|
||||
|
||||
virtual void schedule(gp* payload) = 0;
|
||||
virtual std::pair<Command, gp*> getNextRequest(Bank bank) = 0;
|
||||
static std::string sendername;
|
||||
|
||||
protected:
|
||||
void printDebugMessage(std::string message);
|
||||
Command getNextCommand(gp &payload);
|
||||
Command getNextCommand(gp *payload);
|
||||
|
||||
Command getReadWriteCommand(gp &payload);
|
||||
Command getReadWriteCommand(gp *payload);
|
||||
|
||||
ControllerCore &controllerCore;
|
||||
};
|
||||
|
||||
#endif // ISCHEDULER_H
|
||||
@@ -1,113 +1,112 @@
|
||||
|
||||
// * PARBS.cpp
|
||||
// *
|
||||
// * Created on: Apr 9, 2014
|
||||
// * Author: robert
|
||||
// */
|
||||
//// * PARBS.cpp
|
||||
//// *
|
||||
//// * Created on: Apr 9, 2014
|
||||
//// * Author: robert
|
||||
//// */
|
||||
|
||||
#include "PARBS.h"
|
||||
#include "../core/configuration/Configuration.h"
|
||||
#include "../../common/dramExtension.h"
|
||||
#include "map"
|
||||
#include "ThreadLoad.h"
|
||||
#include <algorithm>
|
||||
//#include "PARBS.h"
|
||||
//#include "../core/configuration/Configuration.h"
|
||||
//#include "../../common/dramExtension.h"
|
||||
//#include "map"
|
||||
//#include "ThreadLoad.h"
|
||||
//#include <algorithm>
|
||||
|
||||
namespace scheduler {
|
||||
//namespace scheduler {
|
||||
|
||||
using namespace std;
|
||||
using namespace core;
|
||||
//using namespace std;
|
||||
|
||||
PAR_BS::PAR_BS(core::ControllerCore& controllerCore, bool useExternalBankstates, unsigned int capsize) :
|
||||
controllerCore(controllerCore), useExternalBankstates(useExternalBankstates), capsize(capsize)
|
||||
{
|
||||
if (useExternalBankstates)
|
||||
{
|
||||
batch = new FR_FCFS(controllerCore, true, false);
|
||||
buffer = new FR_FCFS(controllerCore, true, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
batch = new FR_FCFS(controllerCore, true, false);
|
||||
buffer = new FR_FCFS(controllerCore, true, false);
|
||||
}
|
||||
}
|
||||
//PAR_BS::PAR_BS(ControllerCore& controllerCore, bool useExternalBankstates, unsigned int capsize) :
|
||||
// controllerCore(controllerCore), useExternalBankstates(useExternalBankstates), capsize(capsize)
|
||||
//{
|
||||
// if (useExternalBankstates)
|
||||
// {
|
||||
// batch = new FR_FCFS(controllerCore, true, false);
|
||||
// buffer = new FR_FCFS(controllerCore, true, false);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// batch = new FR_FCFS(controllerCore, true, false);
|
||||
// buffer = new FR_FCFS(controllerCore, true, false);
|
||||
// }
|
||||
//}
|
||||
|
||||
PAR_BS::~PAR_BS()
|
||||
{
|
||||
//PAR_BS::~PAR_BS()
|
||||
//{
|
||||
|
||||
}
|
||||
//}
|
||||
|
||||
bool PAR_BS::hasPayloads()
|
||||
{
|
||||
return batch->hasPayloads() || buffer->hasPayloads();
|
||||
}
|
||||
//bool PAR_BS::hasPayloads()
|
||||
//{
|
||||
// return batch->hasPayloads() || buffer->hasPayloads();
|
||||
//}
|
||||
|
||||
void PAR_BS::schedule(gp* payload)
|
||||
{
|
||||
printDebugMessage("hello!");
|
||||
buffer->schedule(payload);
|
||||
}
|
||||
//void PAR_BS::schedule(gp* payload)
|
||||
//{
|
||||
// printDebugMessage("hello!");
|
||||
// buffer->schedule(payload);
|
||||
//}
|
||||
|
||||
gp* PAR_BS::getNextPayload()
|
||||
{
|
||||
if (!batch->hasPayloads())
|
||||
{
|
||||
stringstream s;
|
||||
s << "In batch: " << batch->getNumberOfQueuedPayloads() << "\t" << "in buffer: " << buffer->getNumberOfQueuedPayloads() << endl;
|
||||
formBatch();
|
||||
s<< "Formed new batch" << endl;
|
||||
s << "In batch: " << batch->getNumberOfQueuedPayloads() << "\t" << "in buffer: " << buffer->getNumberOfQueuedPayloads() << endl;
|
||||
printDebugMessage(s.str());
|
||||
sc_assert(batch->hasPayloads());
|
||||
}
|
||||
//gp* PAR_BS::getNextPayload()
|
||||
//{
|
||||
// if (!batch->hasPayloads())
|
||||
// {
|
||||
// stringstream s;
|
||||
// s << "In batch: " << batch->getNumberOfQueuedPayloads() << "\t" << "in buffer: " << buffer->getNumberOfQueuedPayloads() << endl;
|
||||
// formBatch();
|
||||
// s<< "Formed new batch" << endl;
|
||||
// s << "In batch: " << batch->getNumberOfQueuedPayloads() << "\t" << "in buffer: " << buffer->getNumberOfQueuedPayloads() << endl;
|
||||
// printDebugMessage(s.str());
|
||||
// sc_assert(batch->hasPayloads());
|
||||
// }
|
||||
|
||||
gp* result = batch->getNextPayload();
|
||||
if(result == NULL)
|
||||
result = buffer->getNextPayload();
|
||||
return result;
|
||||
}
|
||||
// gp* result = batch->getNextPayload();
|
||||
// if(result == NULL)
|
||||
// result = buffer->getNextPayload();
|
||||
// return result;
|
||||
//}
|
||||
|
||||
void PAR_BS::removePayload(gp* payload)
|
||||
{
|
||||
buffer->removePayload(payload);
|
||||
batch->removePayload(payload);
|
||||
//void PAR_BS::removePayload(gp* payload)
|
||||
//{
|
||||
// buffer->removePayload(payload);
|
||||
// batch->removePayload(payload);
|
||||
|
||||
if (!useExternalBankstates)
|
||||
{
|
||||
DramExtension& extension = DramExtension::getExtension(payload);
|
||||
internalBankstates.openRowInRowBuffer(extension.getBank(), extension.getRow());
|
||||
}
|
||||
// if (!useExternalBankstates)
|
||||
// {
|
||||
// DramExtension& extension = DramExtension::getExtension(payload);
|
||||
// internalBankstates.openRowInRowBuffer(extension.getBank(), extension.getRow());
|
||||
// }
|
||||
|
||||
}
|
||||
//}
|
||||
|
||||
void PAR_BS::formBatch()
|
||||
{
|
||||
map<Thread, ThreadLoad> loads;
|
||||
//void PAR_BS::formBatch()
|
||||
//{
|
||||
// map<Thread, ThreadLoad> loads;
|
||||
|
||||
for (Bank bank : controllerCore.getBanks())
|
||||
{
|
||||
for (unsigned int i = 0; i < capsize; i++)
|
||||
{
|
||||
gp* payload = buffer->popOldest(bank);
|
||||
if(payload == NULL)
|
||||
break;
|
||||
loads[DramExtension::getExtension(payload).getThread()].addTransaction(payload);
|
||||
}
|
||||
}
|
||||
// for (Bank bank : controllerCore.getBanks())
|
||||
// {
|
||||
// for (unsigned int i = 0; i < capsize; i++)
|
||||
// {
|
||||
// gp* payload = buffer->popOldest(bank);
|
||||
// if(payload == NULL)
|
||||
// break;
|
||||
// loads[DramExtension::getExtension(payload).getThread()].addTransaction(payload);
|
||||
// }
|
||||
// }
|
||||
|
||||
vector<ThreadLoad*> sortedLoads;
|
||||
for (auto& threadLoadPair : loads)
|
||||
{
|
||||
sortedLoads.push_back(&threadLoadPair.second);
|
||||
}
|
||||
// vector<ThreadLoad*> sortedLoads;
|
||||
// for (auto& threadLoadPair : loads)
|
||||
// {
|
||||
// sortedLoads.push_back(&threadLoadPair.second);
|
||||
// }
|
||||
|
||||
sort(sortedLoads.begin(), sortedLoads.end(), LoadPointerComparer());
|
||||
// sort(sortedLoads.begin(), sortedLoads.end(), LoadPointerComparer());
|
||||
|
||||
for (auto& load : sortedLoads)
|
||||
{
|
||||
batch->schedule(load->getTransactions());
|
||||
}
|
||||
// for (auto& load : sortedLoads)
|
||||
// {
|
||||
// batch->schedule(load->getTransactions());
|
||||
// }
|
||||
|
||||
}
|
||||
//}
|
||||
|
||||
}
|
||||
//}
|
||||
|
||||
@@ -1,40 +1,40 @@
|
||||
|
||||
// * PARBS.h
|
||||
// *
|
||||
// * Created on: Apr 9, 2014
|
||||
// * Author: robert
|
||||
// *
|
||||
//// * PARBS.h
|
||||
//// *
|
||||
//// * Created on: Apr 9, 2014
|
||||
//// * Author: robert
|
||||
//// *
|
||||
|
||||
#ifndef PARBS_H_
|
||||
#define PARBS_H_
|
||||
#include "Scheduler.h"
|
||||
#include "../core/ControllerCore.h"
|
||||
#include "Fr_Fcfs.h"
|
||||
//#ifndef PARBS_H_
|
||||
//#define PARBS_H_
|
||||
//#include "Scheduler.h"
|
||||
//#include "../core/ControllerCore.h"
|
||||
//#include "Fr_Fcfs.h"
|
||||
|
||||
namespace scheduler {
|
||||
//namespace scheduler {
|
||||
|
||||
class PAR_BS : public Scheduler
|
||||
{
|
||||
public:
|
||||
PAR_BS(core::ControllerCore& controllerCore, bool useExternalBankstates, unsigned int capsize);
|
||||
virtual ~PAR_BS();
|
||||
//class PAR_BS : public Scheduler
|
||||
//{
|
||||
//public:
|
||||
// PAR_BS(ControllerCore& controllerCore, bool useExternalBankstates, unsigned int capsize);
|
||||
// virtual ~PAR_BS();
|
||||
|
||||
virtual bool hasPayloads() override;
|
||||
virtual void schedule(gp* payload) override;
|
||||
virtual gp* getNextPayload() override;
|
||||
virtual void removePayload(gp* payload) override;
|
||||
// virtual bool hasPayloads() override;
|
||||
// virtual void schedule(gp* payload) override;
|
||||
// virtual gp* getNextPayload() override;
|
||||
// virtual void removePayload(gp* payload) override;
|
||||
|
||||
private:
|
||||
void formBatch();
|
||||
//private:
|
||||
// void formBatch();
|
||||
|
||||
core::ControllerCore& controllerCore;
|
||||
bool useExternalBankstates;
|
||||
core::RowBufferState internalBankstates;
|
||||
FR_FCFS *batch;
|
||||
FR_FCFS *buffer;
|
||||
unsigned int capsize;
|
||||
};
|
||||
// ControllerCore& controllerCore;
|
||||
// bool useExternalBankstates;
|
||||
// RowBufferState internalBankstates;
|
||||
// FR_FCFS *batch;
|
||||
// FR_FCFS *buffer;
|
||||
// unsigned int capsize;
|
||||
//};
|
||||
|
||||
} /* scheduler core */
|
||||
//} /* scheduler core */
|
||||
|
||||
#endif
|
||||
//#endif
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
#include "Scheduler.h"
|
||||
#include "../../common/DebugManager.h"
|
||||
#include <iostream>
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace scheduler;
|
||||
|
||||
std::string Scheduler::sendername = "scheduler";
|
||||
|
||||
void Scheduler::printDebugMessage(std::string message)
|
||||
{
|
||||
//cout << "scheduler: " << message << std::endl;
|
||||
DebugManager::getInstance().printDebugMessage(Scheduler::sendername, message);
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
#ifndef SCHEDULER_H
|
||||
#define SCHEDULER_H
|
||||
#include <tlm.h>
|
||||
#include "../../common/dramExtension.h"
|
||||
|
||||
namespace scheduler {
|
||||
|
||||
typedef tlm::tlm_generic_payload gp;
|
||||
|
||||
class Scheduler
|
||||
{
|
||||
public:
|
||||
virtual ~Scheduler(){}
|
||||
virtual void schedule(gp* payload) = 0;
|
||||
virtual bool hasPayloads() = 0;
|
||||
virtual gp* getNextPayload() = 0;
|
||||
virtual void removePayload(gp* payload) = 0;
|
||||
static std::string sendername;
|
||||
|
||||
protected:
|
||||
void printDebugMessage(std::string message);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif // SCHEDULER_H
|
||||
@@ -1,71 +1,71 @@
|
||||
/*
|
||||
* ThreadLoad.cpp
|
||||
*
|
||||
* Created on: Apr 9, 2014
|
||||
* Author: robert
|
||||
*/
|
||||
|
||||
#include "ThreadLoad.h"
|
||||
// * ThreadLoad.cpp
|
||||
// *
|
||||
// * Created on: Apr 9, 2014
|
||||
// * Author: robert
|
||||
// */
|
||||
|
||||
namespace scheduler {
|
||||
//#include "ThreadLoad.h"
|
||||
|
||||
using namespace std;
|
||||
//namespace scheduler {
|
||||
|
||||
ThreadLoad::ThreadLoad()
|
||||
{
|
||||
// TODO Auto-generated constructor stub
|
||||
//using namespace std;
|
||||
|
||||
}
|
||||
//ThreadLoad::ThreadLoad()
|
||||
//{
|
||||
// // TODO Auto-generated constructor stub
|
||||
|
||||
ThreadLoad::~ThreadLoad()
|
||||
{
|
||||
// TODO Auto-generated destructor stub
|
||||
}
|
||||
//}
|
||||
|
||||
unsigned int ThreadLoad::getMaxBankLoad() const
|
||||
{
|
||||
unsigned int maxLoad = 0;
|
||||
for (auto& bankVectorPair : load)
|
||||
{
|
||||
if (bankVectorPair.second.size() > maxLoad)
|
||||
maxLoad = bankVectorPair.second.size();
|
||||
}
|
||||
return maxLoad;
|
||||
}
|
||||
//ThreadLoad::~ThreadLoad()
|
||||
//{
|
||||
// // TODO Auto-generated destructor stub
|
||||
//}
|
||||
|
||||
unsigned int ThreadLoad::getTotalLoad() const
|
||||
{
|
||||
unsigned int totalLoad = 0;
|
||||
for (auto& bankVectorPair : load)
|
||||
{
|
||||
totalLoad += bankVectorPair.second.size();
|
||||
}
|
||||
return totalLoad;
|
||||
}
|
||||
//unsigned int ThreadLoad::getMaxBankLoad() const
|
||||
//{
|
||||
// unsigned int maxLoad = 0;
|
||||
// for (auto& bankVectorPair : load)
|
||||
// {
|
||||
// if (bankVectorPair.second.size() > maxLoad)
|
||||
// maxLoad = bankVectorPair.second.size();
|
||||
// }
|
||||
// return maxLoad;
|
||||
//}
|
||||
|
||||
void ThreadLoad::addTransaction(gp* payload)
|
||||
{
|
||||
load[DramExtension::getExtension(payload).getBank()].push_back(payload);
|
||||
}
|
||||
//unsigned int ThreadLoad::getTotalLoad() const
|
||||
//{
|
||||
// unsigned int totalLoad = 0;
|
||||
// for (auto& bankVectorPair : load)
|
||||
// {
|
||||
// totalLoad += bankVectorPair.second.size();
|
||||
// }
|
||||
// return totalLoad;
|
||||
//}
|
||||
|
||||
bool operator<(const ThreadLoad& lhs, const ThreadLoad& rhs)
|
||||
{
|
||||
if (lhs.getMaxBankLoad() < rhs.getMaxBankLoad())
|
||||
return true;
|
||||
else if (lhs.getMaxBankLoad() == rhs.getMaxBankLoad())
|
||||
return lhs.getTotalLoad() < rhs.getTotalLoad();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
//void ThreadLoad::addTransaction(gp* payload)
|
||||
//{
|
||||
// load[DramExtension::getExtension(payload).getBank()].push_back(payload);
|
||||
//}
|
||||
|
||||
vector<gp*> ThreadLoad::getTransactions()
|
||||
{
|
||||
vector<gp*> result;
|
||||
for (auto& bankVectorPair : load)
|
||||
{
|
||||
result.insert(result.end(), bankVectorPair.second.begin(), bankVectorPair.second.end());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
//bool operator<(const ThreadLoad& lhs, const ThreadLoad& rhs)
|
||||
//{
|
||||
// if (lhs.getMaxBankLoad() < rhs.getMaxBankLoad())
|
||||
// return true;
|
||||
// else if (lhs.getMaxBankLoad() == rhs.getMaxBankLoad())
|
||||
// return lhs.getTotalLoad() < rhs.getTotalLoad();
|
||||
// else
|
||||
// return false;
|
||||
//}
|
||||
|
||||
} /* namespace scheduler */
|
||||
//vector<gp*> ThreadLoad::getTransactions()
|
||||
//{
|
||||
// vector<gp*> result;
|
||||
// for (auto& bankVectorPair : load)
|
||||
// {
|
||||
// result.insert(result.end(), bankVectorPair.second.begin(), bankVectorPair.second.end());
|
||||
// }
|
||||
// return result;
|
||||
//}
|
||||
|
||||
//} /* namespace scheduler
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
/*
|
||||
* ThreadLoad.h
|
||||
*
|
||||
* Created on: Apr 9, 2014
|
||||
* Author: robert
|
||||
*/
|
||||
|
||||
#ifndef THREADLOAD_H_
|
||||
#define THREADLOAD_H_
|
||||
#include <map>
|
||||
#include <tlm.h>
|
||||
#include "../../common/dramExtension.h"
|
||||
//// * ThreadLoad.h
|
||||
//// *
|
||||
//// * Created on: Apr 9, 2014
|
||||
//// * Author: robert
|
||||
//// */
|
||||
|
||||
namespace scheduler {
|
||||
//#ifndef THREADLOAD_H_
|
||||
//#define THREADLOAD_H_
|
||||
//#include <map>
|
||||
//#include <tlm.h>
|
||||
//#include "../../common/dramExtension.h"
|
||||
|
||||
typedef tlm::tlm_generic_payload gp;
|
||||
//namespace scheduler {
|
||||
|
||||
class ThreadLoad
|
||||
{
|
||||
public:
|
||||
ThreadLoad();
|
||||
virtual ~ThreadLoad();
|
||||
//typedef tlm::tlm_generic_payload gp;
|
||||
|
||||
unsigned int getMaxBankLoad() const;
|
||||
unsigned int getTotalLoad() const;
|
||||
//class ThreadLoad
|
||||
//{
|
||||
//public:
|
||||
// ThreadLoad();d
|
||||
// virtual ~ThreadLoad();
|
||||
|
||||
void addTransaction(gp* payload);
|
||||
std::vector<gp*> getTransactions();
|
||||
// unsigned int getMaxBankLoad() const;
|
||||
// unsigned int getTotalLoad() const;
|
||||
|
||||
private:
|
||||
std::map<Bank,std::vector<gp*>> load;
|
||||
};
|
||||
// void addTransaction(gp* payload);
|
||||
// std::vector<gp*> getTransactions();
|
||||
|
||||
bool operator< (const ThreadLoad &lhs, const ThreadLoad &rhs);
|
||||
//private:
|
||||
// std::map<Bank,std::vector<gp*>> load;
|
||||
//};
|
||||
|
||||
struct LoadPointerComparer {
|
||||
bool operator()(const ThreadLoad* l, const ThreadLoad* r) {
|
||||
return *l < *r;
|
||||
}
|
||||
};
|
||||
//bool operator< (const ThreadLoad &lhs, const ThreadLoad &rhs);
|
||||
|
||||
} /* namespace scheduler */
|
||||
//struct LoadPointerComparer {
|
||||
// bool operator()(const ThreadLoad* l, const ThreadLoad* r) {
|
||||
// return *l < *r;
|
||||
// }
|
||||
//};
|
||||
|
||||
#endif /* THREADLOAD_H_ */
|
||||
//} /* namespace scheduler */
|
||||
|
||||
//#endif /* THREADLOAD_H_
|
||||
|
||||
@@ -1,154 +1,154 @@
|
||||
#include "readwritegrouper.h"
|
||||
#include "../../common/DebugManager.h"
|
||||
//#include "readwritegrouper.h"
|
||||
//#include "../../common/DebugManager.h"
|
||||
|
||||
namespace scheduler{
|
||||
//namespace scheduler{
|
||||
|
||||
using namespace tlm;
|
||||
using namespace std;
|
||||
//using namespace tlm;
|
||||
//using namespace std;
|
||||
|
||||
ReadWriteGrouper::ReadWriteGrouper(core::ControllerCore& controllerCore): controllerCore(controllerCore)
|
||||
{
|
||||
batches.push_back(shared_ptr<FR_FCFS>(new FR_FCFS(controllerCore,true,false)));
|
||||
batches.push_back(shared_ptr<FR_FCFS>(new FR_FCFS(controllerCore,true,false)));
|
||||
}
|
||||
//ReadWriteGrouper::ReadWriteGrouper(ControllerCore& controllerCore): controllerCore(controllerCore)
|
||||
//{
|
||||
// batches.push_back(shared_ptr<FR_FCFS>(new FR_FCFS(controllerCore,true,false)));
|
||||
// batches.push_back(shared_ptr<FR_FCFS>(new FR_FCFS(controllerCore,true,false)));
|
||||
//}
|
||||
|
||||
ReadWriteGrouper::~ReadWriteGrouper()
|
||||
{
|
||||
//ReadWriteGrouper::~ReadWriteGrouper()
|
||||
//{
|
||||
|
||||
}
|
||||
//}
|
||||
|
||||
void ReadWriteGrouper::schedule(gp *payload)
|
||||
{
|
||||
tlm_command command = payload->get_command();
|
||||
//void ReadWriteGrouper::schedule(gp *payload)
|
||||
//{
|
||||
// tlm_command command = payload->get_command();
|
||||
|
||||
if(batches.size() > 2)
|
||||
{
|
||||
if(command == TLM_READ_COMMAND)
|
||||
{
|
||||
//printDebugMessage("Scheduling read");
|
||||
// if(batches.size() > 2)
|
||||
// {
|
||||
// if(command == TLM_READ_COMMAND)
|
||||
// {
|
||||
// //printDebugMessage("Scheduling read");
|
||||
|
||||
if(schedulingReadCausesHazardWithQueuedWrite(payload))
|
||||
{
|
||||
printDebugMessage("Scheduling read causes hazard with queued write");
|
||||
batches.push_back(shared_ptr<FR_FCFS>(new FR_FCFS(controllerCore,true,false)));
|
||||
batches.push_back(shared_ptr<FR_FCFS>(new FR_FCFS(controllerCore,true,false)));
|
||||
}
|
||||
// if(schedulingReadCausesHazardWithQueuedWrite(payload))
|
||||
// {
|
||||
// printDebugMessage("Scheduling read causes hazard with queued write");
|
||||
// batches.push_back(shared_ptr<FR_FCFS>(new FR_FCFS(controllerCore,true,false)));
|
||||
// batches.push_back(shared_ptr<FR_FCFS>(new FR_FCFS(controllerCore,true,false)));
|
||||
// }
|
||||
|
||||
getLatestReadBatch().schedule(payload);
|
||||
}
|
||||
else if(command == TLM_WRITE_COMMAND)
|
||||
{
|
||||
//printDebugMessage("Scheduling write");
|
||||
getLatestWriteBatch().schedule(payload);
|
||||
}
|
||||
}
|
||||
else if(batches.size() == 2)
|
||||
{
|
||||
if(command == TLM_READ_COMMAND)
|
||||
{
|
||||
//printDebugMessage("Scheduling read");
|
||||
// getLatestReadBatch().schedule(payload);
|
||||
// }
|
||||
// else if(command == TLM_WRITE_COMMAND)
|
||||
// {
|
||||
// //printDebugMessage("Scheduling write");
|
||||
// getLatestWriteBatch().schedule(payload);
|
||||
// }
|
||||
// }
|
||||
// else if(batches.size() == 2)
|
||||
// {
|
||||
// if(command == TLM_READ_COMMAND)
|
||||
// {
|
||||
// //printDebugMessage("Scheduling read");
|
||||
|
||||
if(getLatestReadBatch().hasPayloads() && schedulingReadCausesHazardWithQueuedWrite(payload))
|
||||
{
|
||||
printDebugMessage("Scheduling read causes hazard with queued write");
|
||||
batches.push_back(shared_ptr<FR_FCFS>(new FR_FCFS(controllerCore,true,false)));
|
||||
batches.push_back(shared_ptr<FR_FCFS>(new FR_FCFS(controllerCore,true,false)));
|
||||
}
|
||||
else if(!getLatestReadBatch().hasPayloads() && getLatestWriteBatch().hasPayloads())
|
||||
{
|
||||
printDebugMessage("Scheduling read, but there are writes to be processed first");
|
||||
batches.erase(batches.begin());
|
||||
batches.push_back(shared_ptr<FR_FCFS>(new FR_FCFS(controllerCore,true,false)));
|
||||
batches.push_back(shared_ptr<FR_FCFS>(new FR_FCFS(controllerCore,true,false)));
|
||||
}
|
||||
getLatestReadBatch().schedule(payload);
|
||||
// if(getLatestReadBatch().hasPayloads() && schedulingReadCausesHazardWithQueuedWrite(payload))
|
||||
// {
|
||||
// printDebugMessage("Scheduling read causes hazard with queued write");
|
||||
// batches.push_back(shared_ptr<FR_FCFS>(new FR_FCFS(controllerCore,true,false)));
|
||||
// batches.push_back(shared_ptr<FR_FCFS>(new FR_FCFS(controllerCore,true,false)));
|
||||
// }
|
||||
// else if(!getLatestReadBatch().hasPayloads() && getLatestWriteBatch().hasPayloads())
|
||||
// {
|
||||
// printDebugMessage("Scheduling read, but there are writes to be processed first");
|
||||
// batches.erase(batches.begin());
|
||||
// batches.push_back(shared_ptr<FR_FCFS>(new FR_FCFS(controllerCore,true,false)));
|
||||
// batches.push_back(shared_ptr<FR_FCFS>(new FR_FCFS(controllerCore,true,false)));
|
||||
// }
|
||||
// getLatestReadBatch().schedule(payload);
|
||||
|
||||
}
|
||||
else if(command == TLM_WRITE_COMMAND)
|
||||
{
|
||||
//printDebugMessage("Scheduling write");
|
||||
getLatestWriteBatch().schedule(payload);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sc_assert(false);
|
||||
}
|
||||
}
|
||||
// }
|
||||
// else if(command == TLM_WRITE_COMMAND)
|
||||
// {
|
||||
// //printDebugMessage("Scheduling write");
|
||||
// getLatestWriteBatch().schedule(payload);
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// sc_assert(false);
|
||||
// }
|
||||
//}
|
||||
|
||||
gp *ReadWriteGrouper::getNextPayload()
|
||||
{
|
||||
if(batches.size() > 2)
|
||||
{
|
||||
return batches.front()->getNextPayload();
|
||||
}
|
||||
else if(batches.size() == 2)
|
||||
{
|
||||
if(getLatestReadBatch().hasPayloads())
|
||||
return getLatestReadBatch().getNextPayload();
|
||||
else if(getLatestWriteBatch().hasPayloads())
|
||||
return getLatestWriteBatch().getNextPayload();
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
sc_assert(false);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
//gp *ReadWriteGrouper::getNextPayload()
|
||||
//{
|
||||
// if(batches.size() > 2)
|
||||
// {
|
||||
// return batches.front()->getNextPayload();
|
||||
// }
|
||||
// else if(batches.size() == 2)
|
||||
// {
|
||||
// if(getLatestReadBatch().hasPayloads())
|
||||
// return getLatestReadBatch().getNextPayload();
|
||||
// else if(getLatestWriteBatch().hasPayloads())
|
||||
// return getLatestWriteBatch().getNextPayload();
|
||||
// else
|
||||
// return NULL;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// sc_assert(false);
|
||||
// return NULL;
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
void ReadWriteGrouper::removePayload(gp *payload)
|
||||
{
|
||||
if(batches.size() > 2)
|
||||
{
|
||||
batches.front()->removePayload(payload);
|
||||
if(!batches.front()->hasPayloads())
|
||||
batches.erase(batches.begin());
|
||||
}
|
||||
else if(batches.size() == 2)
|
||||
{
|
||||
if(payload->is_read())
|
||||
getLatestReadBatch().removePayload(payload);
|
||||
else
|
||||
getLatestWriteBatch().removePayload(payload);
|
||||
}
|
||||
else
|
||||
{
|
||||
sc_assert(false);
|
||||
}
|
||||
}
|
||||
//void ReadWriteGrouper::removePayload(gp *payload)
|
||||
//{
|
||||
// if(batches.size() > 2)
|
||||
// {
|
||||
// batches.front()->removePayload(payload);
|
||||
// if(!batches.front()->hasPayloads())
|
||||
// batches.erase(batches.begin());
|
||||
// }
|
||||
// else if(batches.size() == 2)
|
||||
// {
|
||||
// if(payload->is_read())
|
||||
// getLatestReadBatch().removePayload(payload);
|
||||
// else
|
||||
// getLatestWriteBatch().removePayload(payload);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// sc_assert(false);
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
bool ReadWriteGrouper::hasPayloads()
|
||||
{
|
||||
if(batches.size() > 2)
|
||||
return true;
|
||||
else if(batches.size() == 2)
|
||||
return (getLatestReadBatch().hasPayloads() || getLatestWriteBatch().hasPayloads());
|
||||
else
|
||||
{
|
||||
sc_assert(false);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
//bool ReadWriteGrouper::hasPayloads()
|
||||
//{
|
||||
// if(batches.size() > 2)
|
||||
// return true;
|
||||
// else if(batches.size() == 2)
|
||||
// return (getLatestReadBatch().hasPayloads() || getLatestWriteBatch().hasPayloads());
|
||||
// else
|
||||
// {
|
||||
// sc_assert(false);
|
||||
// return NULL;
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
bool ReadWriteGrouper::schedulingReadCausesHazardWithQueuedWrite(gp *payload)
|
||||
{
|
||||
sc_assert(payload->is_read());
|
||||
return getLatestWriteBatch().containsPayloadTragetingSameAddress(payload);
|
||||
}
|
||||
//bool ReadWriteGrouper::schedulingReadCausesHazardWithQueuedWrite(gp *payload)
|
||||
//{
|
||||
// sc_assert(payload->is_read());
|
||||
// return getLatestWriteBatch().containsPayloadTragetingSameAddress(payload);
|
||||
//}
|
||||
|
||||
FR_FCFS &ReadWriteGrouper::getLatestWriteBatch()
|
||||
{
|
||||
return *batches[batches.size()-1];
|
||||
}
|
||||
//FR_FCFS &ReadWriteGrouper::getLatestWriteBatch()
|
||||
//{
|
||||
// return *batches[batches.size()-1];
|
||||
//}
|
||||
|
||||
FR_FCFS &ReadWriteGrouper::getLatestReadBatch()
|
||||
{
|
||||
return *batches[batches.size()-2];
|
||||
}
|
||||
//FR_FCFS &ReadWriteGrouper::getLatestReadBatch()
|
||||
//{
|
||||
// return *batches[batches.size()-2];
|
||||
//}
|
||||
|
||||
}
|
||||
//}
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
#ifndef READWRITEGROUPER_H
|
||||
#define READWRITEGROUPER_H
|
||||
#include "Scheduler.h"
|
||||
#include "Fr_Fcfs.h"
|
||||
#include "../core/ControllerCore.h"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
//#ifndef READWRITEGROUPER_H
|
||||
//#define READWRITEGROUPER_H
|
||||
//#include "Scheduler.h"
|
||||
//#include "Fr_Fcfs.h"
|
||||
//#include "../core/ControllerCore.h"
|
||||
//#include <memory>
|
||||
//#include <vector>
|
||||
|
||||
|
||||
namespace scheduler{
|
||||
//namespace scheduler{
|
||||
|
||||
class ReadWriteGrouper : public Scheduler
|
||||
{
|
||||
public:
|
||||
ReadWriteGrouper(core::ControllerCore& controllerCore);
|
||||
~ReadWriteGrouper();
|
||||
virtual void schedule(gp* payload) override;
|
||||
virtual bool hasPayloads() override;
|
||||
virtual gp* getNextPayload() override;
|
||||
virtual void removePayload(gp* payload) override;
|
||||
//class ReadWriteGrouper : public Scheduler
|
||||
//{
|
||||
//public:
|
||||
// ReadWriteGrouper(ControllerCore& controllerCore);
|
||||
// ~ReadWriteGrouper();
|
||||
// virtual void schedule(gp* payload) override;
|
||||
// virtual bool hasPayloads() override;
|
||||
// virtual gp* getNextPayload() override;
|
||||
// virtual void removePayload(gp* payload) override;
|
||||
|
||||
private:
|
||||
// contains batches of requests
|
||||
// last element always contains writes
|
||||
// next-to-last element always contains reads
|
||||
// there are always at least two batches
|
||||
// if there are more than two batches, batches[0] is never empty and
|
||||
// getNextPayload and removePayload are forwarded to batches[0]
|
||||
std::vector<std::shared_ptr<FR_FCFS>> batches;
|
||||
core::ControllerCore& controllerCore;
|
||||
//private:
|
||||
// // contains batches of requests
|
||||
// // last element always contains writes
|
||||
// // next-to-last element always contains reads
|
||||
// // there are always at least two batches
|
||||
// // if there are more than two batches, batches[0] is never empty and
|
||||
// // getNextPayload and removePayload are forwarded to batches[0]
|
||||
// std::vector<std::shared_ptr<FR_FCFS>> batches;
|
||||
// ControllerCore& controllerCore;
|
||||
|
||||
bool schedulingReadCausesHazardWithQueuedWrite(gp* payload);
|
||||
FR_FCFS& getLatestWriteBatch();
|
||||
FR_FCFS& getLatestReadBatch();
|
||||
// bool schedulingReadCausesHazardWithQueuedWrite(gp* payload);
|
||||
// FR_FCFS& getLatestWriteBatch();
|
||||
// FR_FCFS& getLatestReadBatch();
|
||||
|
||||
};
|
||||
//};
|
||||
|
||||
|
||||
}
|
||||
//}
|
||||
|
||||
#endif // READWRITEGROUPER_H
|
||||
//#endif // READWRITEGROUPER_H
|
||||
|
||||
@@ -26,11 +26,12 @@
|
||||
|
||||
using namespace std;
|
||||
using namespace tlm;
|
||||
using namespace core;
|
||||
;
|
||||
using namespace Data;
|
||||
|
||||
|
||||
#define POWER //not better to define in simulation xml? also flag for storage simulation
|
||||
//#define POWER
|
||||
//not better to define in simulation xml? also flag for storage simulation
|
||||
//configuration->PowerAnalysys
|
||||
//configuration->ModelStorage
|
||||
//configuration->ModelErrotInjection
|
||||
|
||||
@@ -23,8 +23,10 @@ MemoryManager::~MemoryManager()
|
||||
delete payload;
|
||||
numberOfFrees++;
|
||||
}
|
||||
DebugManager::getInstance().printDebugMessage("MemomryManager","Number of allocated payloads: " + to_string(numberOfAllocations));
|
||||
DebugManager::getInstance().printDebugMessage("MemomryManager","Number of freed payloads: " + to_string(numberOfFrees));
|
||||
|
||||
//Comment in if you are suspecting a memory leak in the manager
|
||||
//DebugManager::getInstance().printDebugMessage("MemoryManager","Number of allocated payloads: " + to_string(numberOfAllocations));
|
||||
//DebugManager::getInstance().printDebugMessage("MemoryManager","Number of freed payloads: " + to_string(numberOfFrees));
|
||||
}
|
||||
|
||||
gp* MemoryManager::allocate()
|
||||
|
||||
@@ -44,18 +44,6 @@ Simulation::Simulation(sc_module_name /*name*/, string pathToResources, string t
|
||||
void Simulation::setupDebugManager(const string& traceName)
|
||||
{
|
||||
auto& dbg = DebugManager::getInstance();
|
||||
dbg.addToWhiteList(controller->name());
|
||||
dbg.addToWhiteList(player1->name());
|
||||
dbg.addToWhiteList(player2->name());
|
||||
dbg.addToWhiteList(player3->name());
|
||||
dbg.addToWhiteList(player4->name());
|
||||
|
||||
dbg.addToWhiteList(this->name());
|
||||
dbg.addToWhiteList(Scheduler::sendername);
|
||||
dbg.addToWhiteList(TlmRecorder::senderName);
|
||||
dbg.addToWhiteList(ControllerCore::senderName);
|
||||
dbg.addToWhiteList(PowerDownManagerBankwise::senderName);
|
||||
|
||||
dbg.writeToConsole = true;
|
||||
dbg.writeToFile = true;
|
||||
if(dbg.writeToFile)
|
||||
@@ -77,7 +65,6 @@ void Simulation::setupTlmRecorder(const string &traceName, const string &pathToR
|
||||
{
|
||||
TlmRecorder::recordingEnabled = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Simulation::instantiateModules(const string &pathToResources, const std::vector<Device>& devices)
|
||||
@@ -85,10 +72,8 @@ void Simulation::instantiateModules(const string &pathToResources, const std::ve
|
||||
dram = new Dram<>("dram");
|
||||
arbiter = new Arbiter<NumberOfTracePlayers, 128>("arbiter");
|
||||
controller = new Controller<>("controller");
|
||||
//reorder = new ReorderBuffer<>("reorder");
|
||||
|
||||
player1 = new StlPlayer<>("player1", pathToResources + string("traces/") + devices[0].trace, devices[0].clkMhz, this);
|
||||
//player1 = new TraceGenerator<>("player1", 0, this);
|
||||
player2 = new StlPlayer<>("player2", pathToResources + string("traces/") + devices[1].trace, devices[1].clkMhz, this);
|
||||
player3 = new StlPlayer<>("player3", pathToResources + string("traces/") + devices[2].trace, devices[2].clkMhz, this);
|
||||
player4 = new StlPlayer<>("player4", pathToResources + string("traces/") + devices[3].trace, devices[3].clkMhz, this);
|
||||
@@ -97,9 +82,6 @@ void Simulation::instantiateModules(const string &pathToResources, const std::ve
|
||||
void Simulation::bindSockets()
|
||||
{
|
||||
player1->iSocket.bind(arbiter->tSockets[0]);
|
||||
//player1->iSocket.bind(reorder->tSocket);
|
||||
//reorder->iSocket.bind(arbiter->tSockets[0]);
|
||||
|
||||
player2->iSocket.bind(arbiter->tSockets[1]);
|
||||
player3->iSocket.bind(arbiter->tSockets[2]);
|
||||
player4->iSocket.bind(arbiter->tSockets[3]);
|
||||
|
||||
@@ -27,9 +27,6 @@ void SimulationManager::loadSimulationsFromXML(string uri)
|
||||
cout << headline << endl;
|
||||
|
||||
exportPath = getFileName(uri);
|
||||
|
||||
//basePath = boost::filesystem::path(uri).parent_path();
|
||||
|
||||
loadXML(uri, simulationdoc);
|
||||
|
||||
cout << "\t-> parsing simulation objects .." << endl;
|
||||
@@ -52,7 +49,7 @@ void SimulationManager::runSimulations()
|
||||
{
|
||||
for (auto& batch : simulationBatches)
|
||||
{
|
||||
boost::filesystem::path dir(exportPath);// + "/" + batch.simulationName);
|
||||
boost::filesystem::path dir(exportPath);
|
||||
boost::filesystem::create_directories(dir);
|
||||
|
||||
for (auto& dramSetup : batch.dramSetups)
|
||||
@@ -81,8 +78,6 @@ void SimulationManager::parseSimulationBatch(XMLElement* simulation)
|
||||
XMLElement* memconfigs = simulation->FirstChildElement("memconfigs");
|
||||
if(memconfigs == NULL) memconfigs = simulation;
|
||||
|
||||
|
||||
|
||||
for (XMLElement* memspec = memspecs->FirstChildElement("memspec"); memspec != NULL;
|
||||
memspec = memspec->NextSiblingElement("memspec"))
|
||||
{
|
||||
@@ -131,11 +126,6 @@ void SimulationManager::startTraceAnalyzer()
|
||||
{
|
||||
string p = getenv("trace");
|
||||
string run_tpr = p + " -f ";
|
||||
for (auto batch : simulationBatches)
|
||||
{
|
||||
// run_tpr += exportPath + "/" + batch.simulationName + " ";
|
||||
|
||||
}
|
||||
run_tpr += "&";
|
||||
system(run_tpr.c_str());
|
||||
}
|
||||
@@ -157,8 +147,6 @@ void SimulationManager::addTraceSetup(SimulationBatch& batch, tinyxml2::XMLEleme
|
||||
|
||||
void SimulationManager::report(string message)
|
||||
{
|
||||
//DebugManager::getInstance().printDebugMessage("Simulation Manager", message);
|
||||
//if (DebugManager::getInstance().writeToConsole == false)
|
||||
cout << message << endl;
|
||||
}
|
||||
|
||||
|
||||
@@ -104,11 +104,11 @@ StlPlayer<BUSWIDTH>::StlPlayer(sc_module_name /*name*/, string pathToTrace, unsi
|
||||
SC_REPORT_FATAL(0, (string("Could not open trace ") + pathToTrace).c_str());
|
||||
|
||||
if(clkMhz == 0)
|
||||
clk = core::Configuration::getInstance().memSpec.clk;
|
||||
clk = Configuration::getInstance().memSpec.clk;
|
||||
else
|
||||
clk = core::FrequencyToClk(clkMhz);
|
||||
clk = FrequencyToClk(clkMhz);
|
||||
|
||||
this->burstlenght = core::Configuration::getInstance().memSpec.BurstLength;
|
||||
this->burstlenght = Configuration::getInstance().memSpec.BurstLength;
|
||||
}
|
||||
|
||||
#endif // STLPLAYER_H
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user