New RefreshManager logic. A refresh trigger is introduced, which is

scheduled in the future to trigger a schedule of a refresh command. This
allows for more sophisticated refresh logics in the futurer
(postponing).
This commit is contained in:
Janik Schlemminger
2014-03-12 05:12:41 -07:00
parent 9d3c6ca715
commit 4dbc9b8a78
19 changed files with 282 additions and 164 deletions

View File

@@ -19,12 +19,6 @@ struct Configuration
TimingConfiguration Timings;
bool RefreshBankwise = false;
unsigned int getStartAddress(int bank)//TODO utils??
{
//return ColumnSize * BytesSize;???
return 0;
}
};
} /* namespace controller */

View File

@@ -9,7 +9,7 @@
#define CONTROLLER_H_
#include <tlm.h>
#include "scheduling/CommandGenerator.h"
#include "scheduling/CommandSequenceGenerator.h"
#include "scheduling/InternalScheduler.h"
#include "Configuration.h"
#include "scheduling/CommandSequenceScheduler.h"
@@ -30,7 +30,7 @@ private:
Configuration config;
ControllerState state;
CommandGenerator commandGenerator;
CommandSequenceGenerator commandGenerator;
CommandSequenceScheduler commandSequenceScheduler;
RefreshManager refreshManager;
PowerDownManager powerDownManager;

View File

@@ -12,8 +12,26 @@
namespace controller{
struct RefreshTiming
{
RefreshTiming(sc_time tRFC, sc_time tREFI) : tRFC(tRFC), tREFI(tREFI) {}
sc_time tRFC;
sc_time tREFI;
};
struct TimingConfiguration
{
TimingConfiguration()
{
unsigned int numberOfBanks = 8;
for (unsigned int i = 0; i < numberOfBanks; ++i)
{
sc_time tRFC = 18*clk;
sc_time tREFI = sc_time(15.6, SC_US); //TODO align
refreshTimings.push_back(RefreshTiming(tRFC, tREFI));
}
}
sc_time clk = sc_time(6.0, SC_NS); // 166MHz
@@ -22,12 +40,14 @@ struct TimingConfiguration
sc_time tRC = tRP + tRAS;
//Refresh
sc_time tRFC = 18*clk;
sc_time tREF = sc_time(64, SC_MS);
sc_time tREFA = tRP + tRFC;
sc_time tREFB = tRP + tRC;
//sc_time tRFC = 18*clk;
//sc_time tREF = sc_time(64, SC_MS);
//sc_time tREFA = tRP + tRFC;
//sc_time tREFB = tRP + tRC;
sc_time tREFI = tREFA;
//sc_time tREFI = tREFA;
std::vector<RefreshTiming> refreshTimings;
};

15
DRAM/src/core/Utils.cpp Normal file
View File

@@ -0,0 +1,15 @@
/*
* Utils.cpp
*
* Created on: Mar 12, 2014
* Author: jonny
*/
#include "Utils.h"
using namespace common;
unsigned int getStartAddress(Bank bank)
{
return 0;
}

16
DRAM/src/core/Utils.h Normal file
View File

@@ -0,0 +1,16 @@
/*
* Utils.h
*
* Created on: Mar 10, 2014
* Author: jonny
*/
#ifndef UTILS_H_
#define UTILS_H_
#include "common/dramextension.h"
unsigned int getStartAddress(common::Bank bank);
#endif /* UTILS_H_ */

View File

@@ -7,56 +7,36 @@
#include <core/refresh/BankwiseRefreshManager.h>
using namespace common;
using namespace std;
namespace controller {
BankwiseRefreshManager::BankwiseRefreshManager(Configuration& configuration, IInternalScheduler& internalScheduler) : controllerConfiguration(configuration), internalScheduler(internalScheduler), refreshTransactions(configuration.numberOfBanks), lastRefreshs()
/*
BankwiseRefreshManager::BankwiseRefreshManager(vector<RefreshTiming> refreshTimings,
IInternalScheduler& internalScheduler)
{
lastRefreshs.reserve(configuration.numberOfBanks);
for (unsigned int i = 0; i < configuration.numberOfBanks; ++i)
assert(!refreshTimings.empty());
for (unsigned int i = 0; i < refreshTimings.size(); ++i)
{
tlm::tlm_generic_payload& transaction = refreshTransactions[i];
//setup
lastRefreshs.push_back(ScheduledCommand(transaction, Command::Refresh, SC_ZERO_TIME));
RefreshManager manager(refreshTimings.at(i), internalScheduler, Bank(i));
refreshManagerForBanks.push_back(&manager);
}
}
BankwiseRefreshManager::~BankwiseRefreshManager()
{
// TODO Auto-generated destructor stub
}
bool BankwiseRefreshManager::hasCollision(const CommandSchedule& schedule)
{
RefreshManager& manager = refreshManagerForBanks.at(schedule.getBank().ID());
return manager.hasCollision(schedule);
}
sc_time BankwiseRefreshManager::getEarliestStartTime(const CommandSchedule& schedule)
void BankwiseRefreshManager::scheduleRefresh(sc_time time)
{
}
void BankwiseRefreshManager::cb_refreshFinished(tlm::tlm_generic_payload& transaction,
sc_time currentTime)
{
}
void BankwiseRefreshManager::planNextRefresh(ScheduledCommand& refresh)
{
}
void BankwiseRefreshManager::scheduleRefresh(const ScheduledCommand& refresh) const
{
}
void BankwiseRefreshManager::setupTransaction(unsigned int i)
{
refreshTransactions[i].set_address(controllerConfiguration.getStartAddress(i));
refreshTransactions[i].set_command(tlm::TLM_READ_COMMAND);
refreshTransactions[i].set_data_length(0);
refreshTransactions[i].set_response_status(tlm::TLM_OK_RESPONSE);
refreshTransactions[i].set_dmi_allowed(false);
refreshTransactions[i].set_byte_enable_length(0);
refreshTransactions[i].set_streaming_width(0);
}
for (unsigned int i = 0; i < refreshManagerForBanks.size(); ++i)
{
RefreshManager& manager = refreshManagerForBanks.at(i);
manager.scheduleRefresh(time);
}
}*/
} /* namespace controller */

View File

@@ -9,35 +9,25 @@
#define BANKWISEREFRESHMANAGER_H_
#include "IRefreshManager.h"
#include "common/dramextension.h"
#include "RefreshManager.h"
namespace controller {
/*
class BankwiseRefreshManager : public IRefreshManager
{
public:
BankwiseRefreshManager(Configuration& configuration, IInternalScheduler& internalScheduler);
virtual ~BankwiseRefreshManager();
BankwiseRefreshManager(std::vector<RefreshTiming> refreshTimings,
IInternalScheduler& internalScheduler);
virtual ~BankwiseRefreshManager(){}
//internal:
virtual bool hasCollision(const CommandSchedule& schedule);
virtual sc_time getEarliestStartTime(const CommandSchedule& schedule);
//external:
virtual void cb_refreshFinished(tlm::tlm_generic_payload& transaction, sc_time currentTime);
virtual void scheduleRefresh(sc_time time);
private:
Configuration& controllerConfiguration;
IInternalScheduler& internalScheduler;
std::vector<tlm::tlm_generic_payload> refreshTransactions;
std::vector<ScheduledCommand> lastRefreshs;
void planNextRefresh(ScheduledCommand& refresh);
void scheduleRefresh(const ScheduledCommand& refresh) const;
void setupTransaction(unsigned int i);
std::vector<RefreshManager> refreshManagerForBanks;
};
*/
} /* namespace controller */
#endif /* BANKWISEREFRESHMANAGER_H_ */

View File

@@ -21,15 +21,8 @@ class IRefreshManager
public:
virtual ~IRefreshManager() {}
//internal:
virtual bool hasCollision(const CommandSchedule& schedule) = 0;
virtual sc_time getEarliestStartTime(const CommandSchedule& schedule) = 0;
//external:
virtual void cb_refreshFinished(tlm::tlm_generic_payload& transaction, sc_time currentTime) = 0;
private:
virtual void scheduleRefresh(const ScheduledCommand& refresh) const = 0;
virtual void scheduleRefresh(sc_time time) = 0;
};
} /* namespace controller */

View File

@@ -6,63 +6,79 @@
*/
#include <core/refresh/RefreshManager.h>
#include "core/Utils.h"
using namespace common;
namespace controller {
RefreshManager::RefreshManager(const Configuration& configuration, IInternalScheduler& internalScheduler) : controllerConfiguration(configuration), internalScheduler(internalScheduler), lastRefresh(refreshTransaction, Command::Refresh, SC_ZERO_TIME)
RefreshManager::RefreshManager(const RefreshTiming& refreshTiming,
IInternalScheduler& internalScheduler) :
refreshTiming(refreshTiming), internalScheduler(internalScheduler), nextPlannedRefresh(
refreshTransaction, Command::Refresh, SC_ZERO_TIME, refreshTiming.tRFC)
{
setupTransaction();
cb_refreshFinished(refreshTransaction, SC_ZERO_TIME);
//RefreshManager(refreshTiming, internalScheduler, Bank(0)); --> something is overwritten?
setupTransaction(refreshTransaction, Bank(0));
planNextRefresh(nextPlannedRefresh);
}
RefreshManager::RefreshManager(const RefreshTiming& refreshTiming,
IInternalScheduler& internalScheduler, Bank bank) :
refreshTiming(refreshTiming), internalScheduler(internalScheduler), nextPlannedRefresh(
refreshTransaction, Command::Refresh, sc_time(65, SC_MS), refreshTiming.tRFC)
{
setupTransaction(refreshTransaction, bank);
planNextRefresh(nextPlannedRefresh);
}
/*
* Is called from TLM Wrapper when end_refresh is sent from DRAM.
*/
void RefreshManager::cb_refreshFinished(tlm::tlm_generic_payload& transaction, sc_time currentTime)
{
planNextRefresh(lastRefresh);
assert(currentTime < lastRefresh.time);
scheduleRefresh(lastRefresh);
}
/*
* Checks for a scheduled CommandSequence, if there is a collision with a refresh.
* A refresh may be postponed for a certain time, to fit the scheduled sequence anyways,
* depending on the refresh logic.
* Checks for a scheduled CommandSequence, if there is a collision with the current planned,
* not yet scheduled, refresh command. In case of a collision the manager schedules the refresh
* (sends it out) and plans the next refresh. Afterwards the CommandSequence is re-scheduled
* with the new controller state (earliest start time is the end of the just scheduled refresh).
*/
bool RefreshManager::hasCollision(const CommandSchedule& schedule)
{
return true;
if (schedule.getEnd() < nextPlannedRefresh.getStart())
{
return false;
}
else
{
scheduleRefresh(nextPlannedRefresh);
return true;
}
}
/*
* If a scheduled CommandSequence collides, the refresh manager provides the earliest
* start time for the new scheduling of this sequence.
*/
sc_time RefreshManager::getEarliestStartTime(const CommandSchedule& schedule)
void RefreshManager::scheduleRefresh(sc_time time)
{
return SC_ZERO_TIME;
if (time == nextPlannedRefresh.getStart())
scheduleRefresh(nextPlannedRefresh);
}
void RefreshManager::scheduleRefresh(const ScheduledCommand& refresh) const
void RefreshManager::scheduleRefresh(ScheduledCommand& refresh)
{
internalScheduler.scheduleCommand(refresh);
planNextRefresh(refresh);
}
void RefreshManager::planNextRefresh(ScheduledCommand& refresh)
void RefreshManager::planNextRefresh(ScheduledCommand& refresh) //TODO nicer to return the reference ?
{
refresh.time += controllerConfiguration.Timings.tREF;
refresh.delayStart(refreshTiming.tREFI);
internalScheduler.scheduleTrigger(Trigger::RefreshTrigger, refresh.getStart());
}
void RefreshManager::setupTransaction()
void RefreshManager::setupTransaction(tlm::tlm_generic_payload& transaction, Bank bank)
{
refreshTransaction.set_address(0);
refreshTransaction.set_command(tlm::TLM_READ_COMMAND);
refreshTransaction.set_data_length(0);
refreshTransaction.set_response_status(tlm::TLM_OK_RESPONSE);
refreshTransaction.set_dmi_allowed(false);
refreshTransaction.set_byte_enable_length(0);
refreshTransaction.set_streaming_width(0);
transaction.set_address(getStartAddress(bank));
transaction.set_command(tlm::TLM_READ_COMMAND);
transaction.set_data_length(0);
transaction.set_response_status(tlm::TLM_OK_RESPONSE);
transaction.set_dmi_allowed(false);
transaction.set_byte_enable_length(0);
transaction.set_streaming_width(0);
transaction.set_extension(new DramExtension(Thread(0), bank, Row(0), Column(0))); //payload takes ownership
}
} /* namespace controller */

View File

@@ -9,33 +9,31 @@
#define REFRESHMANAGER_H_
#include "IRefreshManager.h"
#include "common/dramextension.h"
namespace controller {
class RefreshManager : public IRefreshManager
{
public:
RefreshManager(const Configuration& configuration, IInternalScheduler& internalScheduler);
virtual ~RefreshManager() {}
RefreshManager(const RefreshTiming& refreshTiming, IInternalScheduler& internalScheduler);
RefreshManager(const RefreshTiming& refreshTiming, IInternalScheduler& internalScheduler, common::Bank bank);
virtual ~RefreshManager(){}
//internal:
virtual bool hasCollision(const CommandSchedule& schedule);
virtual sc_time getEarliestStartTime(const CommandSchedule& schedule);
//external:
virtual void cb_refreshFinished(tlm::tlm_generic_payload& transaction, sc_time currentTime);
virtual void scheduleRefresh(sc_time time);
private:
const Configuration& controllerConfiguration;
const RefreshTiming& refreshTiming;
IInternalScheduler& internalScheduler;
tlm::tlm_generic_payload refreshTransaction;
ScheduledCommand lastRefresh;
ScheduledCommand nextPlannedRefresh;
void scheduleRefresh(ScheduledCommand& refresh);
void planNextRefresh(ScheduledCommand& refresh);
void scheduleRefresh(const ScheduledCommand& refresh) const;
void setupTransaction();
void setupTransaction(tlm::tlm_generic_payload& transaction, common::Bank bank);
};
} /* namespace controller */

View File

@@ -12,23 +12,49 @@
#include "common/dramextension.h"
#include "ScheduledCommand.h"
using namespace common;
namespace controller {
class CommandSchedule {
public:
CommandSchedule();
CommandSchedule(tlm::tlm_generic_payload& transaction) : transaction(transaction) {};
virtual ~CommandSchedule();
void push_back(ScheduledCommand scheduledCommand)
void add(Command command, sc_time time, sc_time executionTime)
{
scheduledCommands.push_back(scheduledCommand);
assert(scheduledCommands.empty() || time >= scheduledCommands.back().getEnd());
scheduledCommands.push_back(ScheduledCommand(transaction, command, time, executionTime));
}
const std::vector<ScheduledCommand>& getScheduledCommands() const
{
return this->scheduledCommands;
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 DramExtension::getExtension(&transaction).getBank();
}
private:
std::vector<ScheduledCommand> scheduledCommands;
const tlm::tlm_generic_payload& transaction;
};
} /* namespace controller */

View File

@@ -1,11 +1,11 @@
/*
* CommandGenerator.cpp
* CommandSequenceGenerator.cpp
*
* Created on: Mar 5, 2014
* Author: jonny
*/
#include "CommandGenerator.h"
#include "CommandSequenceGenerator.h"
#include "common/dramextension.h"
using namespace common;
@@ -13,7 +13,7 @@ using namespace std;
namespace controller {
CommandSequence CommandGenerator::generateCommandSequence(tlm::tlm_generic_payload& transaction)
CommandSequence CommandSequenceGenerator::generateCommandSequence(tlm::tlm_generic_payload& transaction)
{
const DramExtension& extension = DramExtension::getExtension(&transaction);
Bank bank = extension.getBank();
@@ -35,13 +35,13 @@ CommandSequence CommandGenerator::generateCommandSequence(tlm::tlm_generic_paylo
}
}
CommandSequence CommandGenerator::generateCommandSequence(
CommandSequence CommandSequenceGenerator::generateCommandSequence(
tlm::tlm_generic_payload* transaction)
{
return generateCommandSequence(*transaction);
}
CommandSequence CommandGenerator::getBankMissCommandSequence(tlm::tlm_generic_payload& transaction)
CommandSequence CommandSequenceGenerator::getBankMissCommandSequence(tlm::tlm_generic_payload& transaction)
{
vector<Command> result;
result.push_back(Command::Activate);
@@ -49,7 +49,7 @@ CommandSequence CommandGenerator::getBankMissCommandSequence(tlm::tlm_generic_pa
return result;
}
CommandSequence CommandGenerator::getRowMissCommandSequence(tlm::tlm_generic_payload& transaction)
CommandSequence CommandSequenceGenerator::getRowMissCommandSequence(tlm::tlm_generic_payload& transaction)
{
vector<Command> result;
result.push_back(Command::Precharge);
@@ -58,14 +58,14 @@ CommandSequence CommandGenerator::getRowMissCommandSequence(tlm::tlm_generic_pay
return result;
}
CommandSequence CommandGenerator::getRowHitCommandSequence(tlm::tlm_generic_payload& transaction)
CommandSequence CommandSequenceGenerator::getRowHitCommandSequence(tlm::tlm_generic_payload& transaction)
{
vector<Command> result;
result.push_back(getReadWriteCommand(transaction));
return result;
}
Command CommandGenerator::getReadWriteCommand(tlm::tlm_generic_payload& transaction)
Command CommandSequenceGenerator::getReadWriteCommand(tlm::tlm_generic_payload& transaction)
{
if (transaction.get_command() == tlm::tlm_command::TLM_READ_COMMAND)
{

View File

@@ -17,10 +17,10 @@ namespace controller {
typedef std::vector<Command> CommandSequence;
class CommandGenerator {
class CommandSequenceGenerator {
public:
CommandGenerator(const ControllerState& controllerState) : controllerState(controllerState) {};
virtual ~CommandGenerator() {};
CommandSequenceGenerator(const ControllerState& controllerState) : controllerState(controllerState) {};
virtual ~CommandSequenceGenerator() {};
CommandSequence generateCommandSequence(tlm::tlm_generic_payload& transaction);
CommandSequence generateCommandSequence(tlm::tlm_generic_payload* transaction);

View File

@@ -11,12 +11,17 @@ namespace controller {
void InternalScheduler::scheduleCommand(const ScheduledCommand& command)
{
if(command.command == Command::Refresh)
if(command.getCommand() == Command::Refresh)
{
scheduleRefresh(command);
}
}
void InternalScheduler::scheduleTrigger(const Trigger command, sc_time time)
{
}
void InternalScheduler::scheduleRefresh(const ScheduledCommand& command)
{
state.bankStates.closeAllRowBuffers();

View File

@@ -10,6 +10,7 @@
#include "CommandSchedule.h"
#include "core/ControllerState.h"
#include "core/scheduling/Trigger.h"
namespace controller{
@@ -18,6 +19,7 @@ class IInternalScheduler
public:
virtual ~IInternalScheduler() {}
virtual void scheduleCommand(const controller::ScheduledCommand& command) = 0;
virtual void scheduleTrigger(const controller::Trigger trigger, sc_time time) = 0;
};
class InternalScheduler : public IInternalScheduler
@@ -25,6 +27,7 @@ class InternalScheduler : public IInternalScheduler
public:
InternalScheduler(controller::ControllerState& state) : state(state) {}
virtual void scheduleCommand(const controller::ScheduledCommand& command);
virtual void scheduleTrigger(const controller::Trigger trigger, sc_time time);
private:
controller::ControllerState& state;

View File

@@ -11,20 +11,59 @@
#include "Command.h"
#include <systemc.h>
namespace controller{
namespace controller {
struct ScheduledCommand{
ScheduledCommand(const tlm::tlm_generic_payload& transaction, Command command, sc_time time) : transaction(transaction), command(command), time(time){};
class ScheduledCommand
{
public:
ScheduledCommand(const tlm::tlm_generic_payload& transaction, Command command, sc_time time,
sc_time executionTime) :
transaction(transaction), command(command), start(time), executionTime(executionTime)
{
}
const tlm::tlm_generic_payload& transaction;
Command command;
sc_time time;
const sc_time getStart() const
{
return start;
}
void delayStart(sc_time delay)
{
start += delay;
}
const sc_time getEnd() const
{
return start + executionTime;
}
const Command getCommand() const
{
return command;
}
const sc_time getExecutionTime() const
{
return executionTime;
}
const tlm::tlm_generic_payload& getTransaction() const
{
return transaction;
}
inline bool operator==(const ScheduledCommand& b) const
{
return b.command == command && b.time == time;
return b.command == command && b.start == start && b.executionTime == executionTime
&& &b.transaction == &transaction;
}
private:
const tlm::tlm_generic_payload& transaction;
const Command command;
sc_time start;
const sc_time executionTime;
};
} /* namespace controller */

View File

@@ -0,0 +1,17 @@
/*
* Trigger.h
*
* Created on: Mar 11, 2014
* Author: jonny
*/
#ifndef TRIGGER_H_
#define TRIGGER_H_
namespace controller {
enum class Trigger {RefreshTrigger};
} /* namespace controller */
#endif /* TRIGGER_H_ */

View File

@@ -1,5 +1,5 @@
#include <gtest/gtest.h>
#include "core/scheduling/CommandGenerator.h"
#include "core/scheduling/CommandSequenceGenerator.h"
#include "testUtils.h"
#include <vector>
@@ -12,10 +12,10 @@ constexpr unsigned int numberOfBanks = 8;
constexpr tlm::tlm_command READ = tlm::tlm_command::TLM_READ_COMMAND;
constexpr tlm::tlm_command WRITE = tlm::tlm_command::TLM_WRITE_COMMAND;
TEST(CommandGenerator, ReadAndWriteWithRowHit)
TEST(CommandSequenceGenerator, ReadAndWriteWithRowHit)
{
ControllerState state(numberOfBanks);
CommandGenerator generator(state);
CommandSequenceGenerator generator(state);
state.bankStates.openRowInRowBuffer(Bank(0), Row(3));
@@ -30,10 +30,10 @@ TEST(CommandGenerator, ReadAndWriteWithRowHit)
EXPECT_EQ(expected_write, generator.generateCommandSequence(hit_write.get()));
}
TEST(CommandGenerator, ReadAndWriteWithRowMiss)
TEST(CommandSequenceGenerator, ReadAndWriteWithRowMiss)
{
ControllerState state(numberOfBanks);
CommandGenerator generator(state);
CommandSequenceGenerator generator(state);
state.bankStates.openRowInRowBuffer(Bank(0), Row(3));
@@ -48,10 +48,10 @@ TEST(CommandGenerator, ReadAndWriteWithRowMiss)
EXPECT_EQ(expected_write, generator.generateCommandSequence(miss_write.get()));
}
TEST(CommandGenerator, ReadAndWriteWithBankMiss)
TEST(CommandSequenceGenerator, ReadAndWriteWithBankMiss)
{
ControllerState state(numberOfBanks);
CommandGenerator generator(state);
CommandSequenceGenerator generator(state);
state.bankStates.openRowInRowBuffer(Bank(0), Row(3));

View File

@@ -21,6 +21,7 @@ class MockInternalScheduler: public IInternalScheduler
{
public:
MOCK_METHOD1(scheduleCommand, void (const ScheduledCommand& command));
MOCK_METHOD2(scheduleTrigger, void (const Trigger command, sc_time time));
};
TEST(RefreshManager, RefreshIsScheduledAfterStartup)
@@ -28,12 +29,14 @@ TEST(RefreshManager, RefreshIsScheduledAfterStartup)
Configuration config;
MockInternalScheduler internalScheduler;
tlm::tlm_generic_payload trans;
auto init = ScheduledCommand(trans, Command::Refresh, config.Timings.tREF);
EXPECT_CALL(internalScheduler, scheduleTrigger(Trigger::RefreshTrigger, _)).Times(2);
EXPECT_CALL(internalScheduler, scheduleCommand(_));
EXPECT_CALL(internalScheduler, scheduleCommand(init));
//first trigger is scheduled
RefreshManager manager(config.Timings.refreshTimings.at(0), internalScheduler);
RefreshManager manager(config, internalScheduler);
//first refresh is scheduled, second trigger is scheduled
manager.scheduleRefresh(config.Timings.refreshTimings.at(0).tREFI);//call back from wrapper
}
TEST(RefreshManager, FinishedRefreshTriggersNewRefresh)
@@ -43,11 +46,14 @@ TEST(RefreshManager, FinishedRefreshTriggersNewRefresh)
EXPECT_CALL(internalScheduler, scheduleCommand(_)).Times(2);
//schedule first refresh in constructor
RefreshManager manager(config, internalScheduler);
//schedule second refresh in callback (end_refresh)
tlm::tlm_generic_payload trans;
manager.cb_refreshFinished(trans, config.Timings.tREF + config.Timings.tREFA);
//first trigger is scheduled
RefreshManager manager(config.Timings.refreshTimings.at(0), internalScheduler);
//first refresh is scheduled at tREFI (wrapper triggers), second trigger is scheduled
manager.scheduleRefresh(config.Timings.refreshTimings.at(0).tREFI);//call back from wrapper
//second trigger should schedule second refresh (wrapper triggers)
manager.scheduleRefresh(config.Timings.refreshTimings.at(0).tREFI * 2);
}
} /* namespace controller */