Merge branch 'master' of git.rhrk.uni-kl.de:EIT-Wehn/dram.vp.system
This commit is contained in:
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -5,3 +5,6 @@
|
||||
path = DRAMSys/library/src/common/third_party/DRAMPower
|
||||
url = https://github.com/tukl-msd/DRAMPower.git
|
||||
branch = master
|
||||
[submodule "DRAMSys/library/src/common/third_party/json"]
|
||||
path = DRAMSys/library/src/common/third_party/json
|
||||
url = https://github.com/nlohmann/json.git
|
||||
|
||||
@@ -39,3 +39,5 @@ simulator.depends = library
|
||||
# Additional Files:
|
||||
# tests folder (DRAMSys/tests)
|
||||
include(tests/tests.pri)
|
||||
|
||||
DISTFILES += ../README.md
|
||||
|
||||
@@ -55,7 +55,7 @@ class Gem5SimControlDRAMsys: public Gem5SystemC::Gem5SimControl
|
||||
{
|
||||
public:
|
||||
Gem5SimControlDRAMsys(string configFile) :
|
||||
Gem5SystemC::Gem5SimControl("gem5",configFile,0,"MemoryAccess")
|
||||
Gem5SystemC::Gem5SimControl("gem5", configFile, 0, "MemoryAccess")
|
||||
{
|
||||
}
|
||||
|
||||
@@ -66,37 +66,38 @@ public:
|
||||
};
|
||||
|
||||
|
||||
struct AddressOffset: sc_module
|
||||
{
|
||||
private:
|
||||
struct AddressOffset: sc_module {
|
||||
private:
|
||||
unsigned long long int offset;
|
||||
|
||||
public:
|
||||
public:
|
||||
tlm_utils::simple_target_socket<AddressOffset> t_socket;
|
||||
tlm_utils::simple_initiator_socket<AddressOffset> i_socket;
|
||||
|
||||
AddressOffset(sc_module_name, unsigned long long int o) : offset(o),t_socket("t_socket"),i_socket("i_socket")
|
||||
AddressOffset(sc_module_name, unsigned long long int o) : offset(o),
|
||||
t_socket("t_socket"), i_socket("i_socket")
|
||||
{
|
||||
t_socket.register_nb_transport_fw(this,&AddressOffset::nb_transport_fw);
|
||||
t_socket.register_transport_dbg(this,&AddressOffset::transport_dbg);
|
||||
t_socket.register_b_transport(this,&AddressOffset::b_transport);
|
||||
i_socket.register_nb_transport_bw(this,&AddressOffset::nb_transport_bw);
|
||||
t_socket.register_nb_transport_fw(this, &AddressOffset::nb_transport_fw);
|
||||
t_socket.register_transport_dbg(this, &AddressOffset::transport_dbg);
|
||||
t_socket.register_b_transport(this, &AddressOffset::b_transport);
|
||||
i_socket.register_nb_transport_bw(this, &AddressOffset::nb_transport_bw);
|
||||
}
|
||||
|
||||
//Forward Interface
|
||||
tlm::tlm_sync_enum nb_transport_fw(tlm_generic_payload &trans, tlm_phase &phase, sc_time &delay)
|
||||
tlm::tlm_sync_enum nb_transport_fw(tlm_generic_payload &trans, tlm_phase &phase,
|
||||
sc_time &delay)
|
||||
{
|
||||
//std::cout << "NB "<< this->name() <<": " << trans.get_address() << " -" << offset;
|
||||
trans.set_address(trans.get_address()-offset);
|
||||
trans.set_address(trans.get_address() - offset);
|
||||
//std::cout << " = " << trans.get_address() << std::endl;
|
||||
return i_socket->nb_transport_fw(trans,phase,delay);
|
||||
return i_socket->nb_transport_fw(trans, phase, delay);
|
||||
}
|
||||
|
||||
unsigned int transport_dbg(tlm::tlm_generic_payload &trans)
|
||||
{
|
||||
// adjust address offset:
|
||||
//std::cout << "Debug "<< this->name() <<": " << trans.get_address() << " -" << offset;
|
||||
trans.set_address(trans.get_address()-offset);
|
||||
trans.set_address(trans.get_address() - offset);
|
||||
//std::cout << " = " << trans.get_address() << std::endl;
|
||||
return i_socket->transport_dbg(trans);
|
||||
}
|
||||
@@ -105,16 +106,17 @@ struct AddressOffset: sc_module
|
||||
{
|
||||
// adjust address offset:
|
||||
//std::cout << "B "<< this->name() <<": " << trans.get_address() << " -" << offset;
|
||||
trans.set_address(trans.get_address()-offset);
|
||||
trans.set_address(trans.get_address() - offset);
|
||||
//std::cout << " = " << trans.get_address() << std::endl;
|
||||
i_socket->b_transport(trans, delay);
|
||||
}
|
||||
|
||||
//Backward Interface
|
||||
tlm::tlm_sync_enum nb_transport_bw(tlm_generic_payload &trans, tlm_phase &phase, sc_time &delay)
|
||||
tlm::tlm_sync_enum nb_transport_bw(tlm_generic_payload &trans, tlm_phase &phase,
|
||||
sc_time &delay)
|
||||
{
|
||||
//trans.set_address(trans.get_address()+offset);
|
||||
return t_socket->nb_transport_bw(trans,phase,delay);
|
||||
return t_socket->nb_transport_bw(trans, phase, delay);
|
||||
}
|
||||
|
||||
};
|
||||
@@ -132,18 +134,15 @@ int sc_main(int argc, char **argv)
|
||||
string gem5ConfigFile;
|
||||
string resources;
|
||||
|
||||
if(argc > 1)
|
||||
{
|
||||
if (argc > 1) {
|
||||
// Get path of resources:
|
||||
resources = pathOfFile(argv[0])
|
||||
+ string("/../../DRAMSys/library/resources/");
|
||||
+ string("/../../DRAMSys/library/resources/");
|
||||
|
||||
SimulationXML = argv[1];
|
||||
gem5ConfigFile = argv[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
SC_REPORT_FATAL("sc_main","Please provide configuration files");
|
||||
} else {
|
||||
SC_REPORT_FATAL("sc_main", "Please provide configuration files");
|
||||
}
|
||||
|
||||
// Instantiate DRAMSys:
|
||||
@@ -177,8 +176,8 @@ int sc_main(int argc, char **argv)
|
||||
Gem5SystemC::Gem5SlaveTransactor dramInterface("transactor1", "transactor1");
|
||||
Gem5SystemC::Gem5SlaveTransactor nvmInterface("transactor2", "transactor2");
|
||||
|
||||
AddressOffset nvmOffset("nvmOffset",0);
|
||||
AddressOffset dramOffset("dramOffset", (2147483648-67108863));//+67108863);
|
||||
AddressOffset nvmOffset("nvmOffset", 0);
|
||||
AddressOffset dramOffset("dramOffset", (2147483648 - 67108863)); //+67108863);
|
||||
|
||||
dramInterface.socket.bind(dramOffset.t_socket);
|
||||
dramOffset.i_socket.bind(dramSys.tSocket); // ID0
|
||||
@@ -194,9 +193,8 @@ int sc_main(int argc, char **argv)
|
||||
sc_core::sc_set_stop_mode(SC_STOP_FINISH_DELTA);
|
||||
sc_core::sc_start();
|
||||
|
||||
if (!sc_core::sc_end_of_simulation_invoked())
|
||||
{
|
||||
SC_REPORT_INFO("sc_main","Simulation stopped without explicit sc_stop()");
|
||||
if (!sc_core::sc_end_of_simulation_invoked()) {
|
||||
SC_REPORT_INFO("sc_main", "Simulation stopped without explicit sc_stop()");
|
||||
sc_core::sc_stop();
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ INCLUDEPATH += $${systemc_home}/include
|
||||
|
||||
INCLUDEPATH += src/common/third_party/DRAMPower/src
|
||||
INCLUDEPATH += src/common/third_party/DRAMPower/src/libdrampower
|
||||
INCLUDEPATH += src/common/third_party/json/include
|
||||
|
||||
DEFINES += TIXML_USE_STL
|
||||
DEFINES += SC_INCLUDE_DYNAMIC_PROCESSES
|
||||
@@ -119,7 +120,9 @@ SOURCES += \
|
||||
src/error/eccbaseclass.cpp \
|
||||
src/error/ecchamming.cpp \
|
||||
src/controller/scheduler/Fr_Fcfs_read_priority.cpp \
|
||||
src/controller/scheduler/Fr_Fcfs_grouper.cpp
|
||||
src/controller/scheduler/Fr_Fcfs_grouper.cpp \
|
||||
src/common/AddressDecoder.cpp \
|
||||
src/common/jsonAddressDecoder.cpp
|
||||
|
||||
HEADERS += \
|
||||
src/common/third_party/tinyxml2/tinyxml2.h \
|
||||
@@ -192,7 +195,10 @@ HEADERS += \
|
||||
src/controller/scheduler/Fr_Fcfs_read_priority.h \
|
||||
src/controller/scheduler/Fr_Fcfs_grouper.h \
|
||||
src/simulation/IArbiter.h \
|
||||
src/simulation/SimpleArbiter.h
|
||||
src/simulation/SimpleArbiter.h \
|
||||
src/common/AddressDecoder.h \
|
||||
src/common/jsonAddressDecoder.h
|
||||
#src/common/third_party/json/include/nlohmann/json.hpp \
|
||||
|
||||
thermalsim = $$(THERMALSIM)
|
||||
isEmpty(thermalsim) {
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"Config": {
|
||||
"numberOfBankBits": 3,
|
||||
"numberOfRowBits": 14,
|
||||
"numberOfColumnBits": 10,
|
||||
"numberOfByteBits": 3,
|
||||
"numberOfBLBits": 3
|
||||
},
|
||||
"Name": "merged_sorted",
|
||||
"Solutions": [
|
||||
{
|
||||
"XOR": [
|
||||
],
|
||||
"Banks Rows": [
|
||||
{
|
||||
"bank_bits": [
|
||||
27,
|
||||
28,
|
||||
29
|
||||
],
|
||||
"rows": {
|
||||
"row_bits": [
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26
|
||||
],
|
||||
"costs": 477468
|
||||
},
|
||||
"costs": 477468
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -32,6 +32,7 @@ OTHER_FILES += resources/scripts/DRAMSylva/README
|
||||
OTHER_FILES += resources/scripts/DRAMSylva/DRAMSylva.patch
|
||||
OTHER_FILES += resources/scripts/DRAMSylva/DRAMSylva.sh
|
||||
OTHER_FILES += resources/scripts/DRAMSylva/DRAMSylvaCSVPlot.py
|
||||
OTHER_FILES += resources/scripts/trace_gen.py
|
||||
|
||||
# Trace Files
|
||||
OTHER_FILES += resources/traces/chstone-aes_32.stl
|
||||
@@ -173,4 +174,5 @@ DISTFILES += \
|
||||
$$PWD/simulations/lpddr4-single-device.xml \
|
||||
$$PWD/configs/amconfigs/am_lpddr4.xml \
|
||||
$$PWD/configs/memspecs/MICRON_6Gb_LPDDR4-3200_NDA_NDA_NDA.xml \
|
||||
$$PWD/scripts/traceGenerationForNNTraining.pl
|
||||
$$PWD/scripts/traceGenerationForNNTraining.pl \
|
||||
$$PWD/configs/amconfigs/am_test_congen_output.json
|
||||
|
||||
137
DRAMSys/library/resources/scripts/trace_gen.py
Executable file
137
DRAMSys/library/resources/scripts/trace_gen.py
Executable file
@@ -0,0 +1,137 @@
|
||||
#! /usr/bin/env python3
|
||||
# vim: set fileencoding=utf-8
|
||||
|
||||
# Copyright (c) 2018, University of Kaiserslautern
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# Author: Éder F. Zulian
|
||||
|
||||
import ctypes
|
||||
|
||||
# A trace file is a pre-recorded file containing memory transactions. Each
|
||||
# memory transaction has a timestamp that tells the simulator when it shall
|
||||
# happen, a transaction type (read or write) and a memory address given in
|
||||
# hexadecimal.
|
||||
#
|
||||
# Here is an example syntax:
|
||||
#
|
||||
# ```
|
||||
# # Comment lines begin with #
|
||||
# # [clock-cyle]: [write|read] [hex-address]
|
||||
# 31: read 0x400140
|
||||
# 33: read 0x400160
|
||||
# 56: write 0x7fff8000
|
||||
# 81: read 0x400180
|
||||
# ```
|
||||
#
|
||||
# The timestamp corresponds to the time the request is to be issued and it is
|
||||
# given in cycles of the bus master device. Example: the device is a FPGA with
|
||||
# frequency 200 MHz (clock period of 5 ns). If the timestamp is 10 it means
|
||||
# that the request is to be issued when time is 50 ns.
|
||||
#
|
||||
|
||||
# The default values given as example assume the following address mapping:
|
||||
#
|
||||
# DIMM Characteristics:
|
||||
# Byte Offset (Y): 8 [0:2] (8-byte-wide memory module, i.e., 64-bit-wide data bus) -> 3 bit
|
||||
# Cols (C): 1K [3:12] (A0 - A9) -> 10 bit
|
||||
# Rows (R): 128K [13:29] (A0 - A16) -> 17 bit
|
||||
# Bank (B): 8 [30:32] (BA0 - BA2) -> 3 bit
|
||||
#
|
||||
# 3 3 3 | 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 | 1 1 1
|
||||
# 2 1 0 | 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 | 2 1 0 9 8 7 6 5 4 3 | 2 1 0
|
||||
# B B B | R R R R R R R R R R R R R R R R R | C C C C C C C C C C | Y Y Y
|
||||
#
|
||||
|
||||
# Transaction type (read or write)
|
||||
transaction = 'read'
|
||||
|
||||
# Channel information. If your address mapping does not have channel bits keep
|
||||
# it equal to 1 and set the shift to the extreme left of the address.
|
||||
num_ch = 1 # Number of channels
|
||||
ch_shift = 34 # Shift to reach the frist bit reserved for channels in the address
|
||||
ch_mask = 0x1 # Mask for all channel bits in the address
|
||||
|
||||
# Bank group information. If your address mapping does not have bank groups
|
||||
# keep it equal to 1 and set the shift to the extreme left of the address.
|
||||
num_bank_groups = 1 # Number of bank groups
|
||||
bgroup_shift = 33 # Shift to reach the frist bit reserved for bank groups in the address
|
||||
bgroup_mask = 0x1 # Mask for all bits in the address related to bank groups
|
||||
|
||||
# Bank information
|
||||
num_banks = 8 # Number of banks
|
||||
bank_shift = 30 # Shift to reach the frist bit reserved for banks in the address
|
||||
bank_mask = 0x7 # Mask for all bank bits in the address
|
||||
|
||||
# Row information
|
||||
num_rows = 128 * 1024 # Number of rows
|
||||
row_shift = 13 # Shift to reach the frist bit reserved for rows in the address
|
||||
row_mask = 0x1ffff # Mask for all row bits in the address
|
||||
|
||||
# Column information
|
||||
num_col = 1 * 1024 # Number of columns
|
||||
col_shift = 3 # Shift to reach the frist bit reserved for columns in the address
|
||||
col_mask = 0x3ff # Mask for all column bits in the address
|
||||
|
||||
# Burst length of 8 columns. 8 columns written/read per access (in 4 full
|
||||
# clock cycles of the memory bus).
|
||||
burst_len = 8
|
||||
|
||||
# Initial clock cycle
|
||||
clock_cycle = 0
|
||||
|
||||
# Clock cycle increment between two accesses
|
||||
clock_increment = 10
|
||||
|
||||
|
||||
def clear_bits(mask, shift, val):
|
||||
m = ctypes.c_uint64(~(mask << shift)).value
|
||||
return ctypes.c_uint64(val & m).value
|
||||
|
||||
|
||||
def set_bits(mask, shift, val, v):
|
||||
val = clear_bits(mask, shift, val)
|
||||
return ctypes.c_uint64(val | (v << shift)).value
|
||||
|
||||
|
||||
address = 0
|
||||
for ch in range(0, num_ch):
|
||||
address = set_bits(ch_mask, ch_shift, address, ch)
|
||||
for bg in range(0, num_bank_groups):
|
||||
address = set_bits(bgroup_mask, bgroup_shift, address, bg)
|
||||
for b in range(0, num_banks):
|
||||
address = set_bits(bank_mask, bank_shift, address, b)
|
||||
for row in range(0, num_rows):
|
||||
address = set_bits(row_mask, row_shift, address, row)
|
||||
for col in range(0, num_col, burst_len):
|
||||
address = set_bits(col_mask, col_shift, address, col)
|
||||
print('# clock cycle: {0:d} | {1} | address: 0x{2:010X} | channel: {3} | bank group: {4} | bank: {5} | row: {6} | column: {7}'.format(clock_cycle, transaction, address, ch, bg, b, row, col))
|
||||
print('{0:d}:\t{1}\t0x{2:010X}'.format(clock_cycle, transaction, address))
|
||||
clock_cycle = clock_cycle + clock_increment
|
||||
67
DRAMSys/library/src/common/AddressDecoder.cpp
Normal file
67
DRAMSys/library/src/common/AddressDecoder.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2018, University of Kaiserslautern
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Authors:
|
||||
* Johannes Feldmann
|
||||
*/
|
||||
|
||||
#include "AddressDecoder.h"
|
||||
#include "xmlAddressdecoder.h"
|
||||
#include "jsonAddressDecoder.h"
|
||||
|
||||
AddressDecoder *AddressDecoder::m_pInstance = nullptr;
|
||||
|
||||
AddressDecoder &AddressDecoder::getInstance()
|
||||
{
|
||||
assert(m_pInstance != nullptr);
|
||||
return *m_pInstance;
|
||||
}
|
||||
|
||||
void AddressDecoder::createInstance(Type t)
|
||||
{
|
||||
assert(m_pInstance == nullptr);
|
||||
switch (t) {
|
||||
case Type::XML:
|
||||
m_pInstance = new xmlAddressDecoder;
|
||||
break;
|
||||
case Type::JSON:
|
||||
m_pInstance = new JSONAddressDecoder;
|
||||
break;
|
||||
default:
|
||||
throw std::logic_error("Instance type not supported.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
AddressDecoder::AddressDecoder()
|
||||
{
|
||||
|
||||
}
|
||||
91
DRAMSys/library/src/common/AddressDecoder.h
Normal file
91
DRAMSys/library/src/common/AddressDecoder.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2018, University of Kaiserslautern
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Authors:
|
||||
* Johannes Feldmann
|
||||
*/
|
||||
|
||||
#ifndef ADDRESSDECODER_H
|
||||
#define ADDRESSDECODER_H
|
||||
|
||||
#include <tlm.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
struct DecodedAddress {
|
||||
DecodedAddress() : channel(0),
|
||||
rank(0),
|
||||
bankgroup(0),
|
||||
row(0),
|
||||
bank(0),
|
||||
column(0),
|
||||
bytes(0)
|
||||
{
|
||||
}
|
||||
|
||||
unsigned int channel;
|
||||
unsigned int rank;
|
||||
unsigned int bankgroup;
|
||||
unsigned int row;
|
||||
unsigned int bank;
|
||||
unsigned int column;
|
||||
unsigned int bytes;
|
||||
};
|
||||
|
||||
class AddressDecoder
|
||||
{
|
||||
public:
|
||||
enum class Type {
|
||||
XML,
|
||||
JSON
|
||||
};
|
||||
|
||||
protected:
|
||||
AddressDecoder();
|
||||
|
||||
static AddressDecoder *m_pInstance;
|
||||
public:
|
||||
static AddressDecoder &getInstance();
|
||||
static void createInstance(Type t);
|
||||
|
||||
virtual void setConfiguration(std::string url) = 0;
|
||||
|
||||
virtual DecodedAddress decodeAddress(sc_dt::uint64 addr) = 0;
|
||||
virtual sc_dt::uint64 encodeAddress(DecodedAddress n) = 0;
|
||||
|
||||
virtual void print() = 0;
|
||||
|
||||
std::map<std::string, unsigned int> amount;
|
||||
};
|
||||
|
||||
#endif // ADDRESSDECODER_H
|
||||
@@ -40,37 +40,38 @@ using namespace std;
|
||||
|
||||
void DebugManager::printDebugMessage(string sender, string message)
|
||||
{
|
||||
if(Configuration::getInstance().Debug)
|
||||
{
|
||||
if (Configuration::getInstance().Debug) {
|
||||
if (writeToConsole)
|
||||
cout << " at " << sc_time_stamp() << "\t in " << sender << "\t: " << message << endl;
|
||||
cout << " at " << sc_time_stamp() << "\t in " << sender << "\t: " << message <<
|
||||
endl;
|
||||
|
||||
if (writeToFile && debugFile)
|
||||
debugFile << " at " << sc_time_stamp() << " in " << sender << "\t: " << message << "\n";
|
||||
debugFile << " at " << sc_time_stamp() << " in " << sender << "\t: " << message
|
||||
<< "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void DebugManager::printMessage(string sender, string message)
|
||||
{
|
||||
cout << " at " << sc_time_stamp() << "\t in " << sender << "\t: " << message << endl;
|
||||
cout << " at " << sc_time_stamp() << "\t in " << sender << "\t: " << message <<
|
||||
endl;
|
||||
}
|
||||
|
||||
void DebugManager::openDebugFile(string filename)
|
||||
{
|
||||
if(debugFile)
|
||||
if (debugFile)
|
||||
debugFile.close();
|
||||
debugFile.open(filename);
|
||||
}
|
||||
|
||||
DebugManager::DebugManager() :
|
||||
writeToConsole(true), writeToFile(true)
|
||||
writeToConsole(true), writeToFile(true)
|
||||
{
|
||||
}
|
||||
|
||||
DebugManager::~DebugManager()
|
||||
{
|
||||
if (writeToFile)
|
||||
{
|
||||
if (writeToFile) {
|
||||
debugFile.flush();
|
||||
debugFile.close();
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ public:
|
||||
|
||||
private:
|
||||
DebugManager();
|
||||
DebugManager(const DebugManager&){}
|
||||
DebugManager(const DebugManager &) {}
|
||||
|
||||
ofstream debugFile;
|
||||
};
|
||||
|
||||
@@ -48,13 +48,16 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
TlmRecorder::TlmRecorder(sc_module_name /*name*/, string uri, string dbname, bool recenable) : sqlScriptURI(uri), dbName(dbname), recordingEnabled(recenable), totalNumTransactions(1), simulationTimeCoveredByRecording(SC_ZERO_TIME)
|
||||
TlmRecorder::TlmRecorder(sc_module_name /*name*/, string uri, string dbname,
|
||||
bool recenable) : sqlScriptURI(uri), dbName(dbname),
|
||||
recordingEnabled(recenable), totalNumTransactions(1),
|
||||
simulationTimeCoveredByRecording(SC_ZERO_TIME)
|
||||
{
|
||||
if (TlmRecorder::recordingEnabled == true) {
|
||||
recordedData.reserve(transactionCommitRate);
|
||||
setUpTransactionTerminatingPhases();
|
||||
openDB(TlmRecorder::dbName.c_str());
|
||||
char * sErrMsg;
|
||||
char *sErrMsg;
|
||||
sqlite3_exec(db, "PRAGMA main.page_size = 4096", NULL, NULL, &sErrMsg);
|
||||
sqlite3_exec(db, "PRAGMA main.cache_size=10000", NULL, NULL, &sErrMsg);
|
||||
sqlite3_exec(db, "PRAGMA main.locking_mode=EXCLUSIVE", NULL, NULL, &sErrMsg);
|
||||
@@ -72,16 +75,6 @@ TlmRecorder::~TlmRecorder()
|
||||
{
|
||||
if (db)
|
||||
closeConnection();
|
||||
sqlite3_finalize(insertTransactionStatement);
|
||||
sqlite3_finalize(insertRangeStatement);
|
||||
sqlite3_finalize(updateRangeStatement);
|
||||
sqlite3_finalize(insertPhaseStatement);
|
||||
sqlite3_finalize(updatePhaseStatement);
|
||||
sqlite3_finalize(insertGeneralInfoStatement);
|
||||
sqlite3_finalize(insertDebugMessageStatement);
|
||||
sqlite3_finalize(updateDataStrobeStatement);
|
||||
sqlite3_finalize(insertPowerStatement);
|
||||
|
||||
}
|
||||
|
||||
void TlmRecorder::recordPower(double timeInSeconds, double averagePower)
|
||||
@@ -93,10 +86,10 @@ void TlmRecorder::recordPower(double timeInSeconds, double averagePower)
|
||||
}
|
||||
}
|
||||
|
||||
void TlmRecorder::recordPhase(tlm::tlm_generic_payload& trans, tlm::tlm_phase phase, sc_time time)
|
||||
void TlmRecorder::recordPhase(tlm::tlm_generic_payload &trans,
|
||||
tlm::tlm_phase phase, sc_time time)
|
||||
{
|
||||
if(TlmRecorder::recordingEnabled)
|
||||
{
|
||||
if (TlmRecorder::recordingEnabled) {
|
||||
if (currentTransactionsInSystem.count(&trans) == 0)
|
||||
introduceTransactionSystem(trans);
|
||||
|
||||
@@ -104,17 +97,14 @@ void TlmRecorder::recordPhase(tlm::tlm_generic_payload& trans, tlm::tlm_phase ph
|
||||
string phaseBeginPrefix = "BEGIN_";
|
||||
string phaseEndPrefix = "END_";
|
||||
|
||||
if (phaseName.find(phaseBeginPrefix) != string::npos)
|
||||
{
|
||||
if (phaseName.find(phaseBeginPrefix) != string::npos) {
|
||||
phaseName.erase(0, phaseBeginPrefix.length());
|
||||
assert(currentTransactionsInSystem.count(&trans) != 0);
|
||||
currentTransactionsInSystem[&trans].insertPhase(phaseName,time);
|
||||
}
|
||||
else
|
||||
{
|
||||
currentTransactionsInSystem[&trans].insertPhase(phaseName, time);
|
||||
} else {
|
||||
phaseName.erase(0, phaseEndPrefix.length());
|
||||
assert(currentTransactionsInSystem.count(&trans) != 0);
|
||||
currentTransactionsInSystem[&trans].setPhaseEnd(phaseName,time);
|
||||
currentTransactionsInSystem[&trans].setPhaseEnd(phaseName, time);
|
||||
}
|
||||
|
||||
bool phaseTerminatesTransaction = count(transactionTerminatingPhases.begin(),
|
||||
@@ -127,10 +117,10 @@ void TlmRecorder::recordPhase(tlm::tlm_generic_payload& trans, tlm::tlm_phase ph
|
||||
}
|
||||
|
||||
|
||||
void TlmRecorder::updateDataStrobe(const sc_time& begin,const sc_time& end, tlm::tlm_generic_payload& trans)
|
||||
void TlmRecorder::updateDataStrobe(const sc_time &begin, const sc_time &end,
|
||||
tlm::tlm_generic_payload &trans)
|
||||
{
|
||||
if(TlmRecorder::recordingEnabled)
|
||||
{
|
||||
if (TlmRecorder::recordingEnabled) {
|
||||
assert(currentTransactionsInSystem.count(&trans) != 0);
|
||||
currentTransactionsInSystem[&trans].timeOnDataStrobe.start = begin;
|
||||
currentTransactionsInSystem[&trans].timeOnDataStrobe.end = end;
|
||||
@@ -140,44 +130,48 @@ void TlmRecorder::updateDataStrobe(const sc_time& begin,const sc_time& end, tlm:
|
||||
|
||||
void TlmRecorder::recordDebugMessage(std::string message, sc_time time)
|
||||
{
|
||||
if(TlmRecorder::recordingEnabled)
|
||||
if (TlmRecorder::recordingEnabled)
|
||||
insertDebugMessageInDB(message, time);
|
||||
}
|
||||
|
||||
|
||||
// ------------- internal -----------------------
|
||||
|
||||
void TlmRecorder::introduceTransactionSystem(tlm::tlm_generic_payload& trans)
|
||||
void TlmRecorder::introduceTransactionSystem(tlm::tlm_generic_payload &trans)
|
||||
{
|
||||
unsigned int id = totalNumTransactions++;
|
||||
currentTransactionsInSystem[&trans].id = id;
|
||||
currentTransactionsInSystem[&trans].address = trans.get_address();
|
||||
currentTransactionsInSystem[&trans].burstlength = trans.get_streaming_width();
|
||||
currentTransactionsInSystem[&trans].dramExtension = DramExtension::getExtension(trans);
|
||||
currentTransactionsInSystem[&trans].dramExtension = DramExtension::getExtension(
|
||||
trans);
|
||||
|
||||
if(DramExtension::getExtension(trans).getThread().ID() == Controller::ControllerThreadId())
|
||||
if (DramExtension::getExtension(trans).getThread().ID() ==
|
||||
Controller::ControllerThreadId())
|
||||
currentTransactionsInSystem[&trans].timeOfGeneration = SC_ZERO_TIME;
|
||||
else
|
||||
currentTransactionsInSystem[&trans].timeOfGeneration = GenerationExtension::getExtension(&trans).TimeOfGeneration();
|
||||
currentTransactionsInSystem[&trans].timeOfGeneration =
|
||||
GenerationExtension::getExtension(&trans).TimeOfGeneration();
|
||||
|
||||
printDebugMessage("New transaction #" + to_string(id) + " generation time " + currentTransactionsInSystem[&trans].timeOfGeneration.to_string());
|
||||
printDebugMessage("New transaction #" + to_string(id) + " generation time " +
|
||||
currentTransactionsInSystem[&trans].timeOfGeneration.to_string());
|
||||
|
||||
if (id % transactionCommitRate == 0)
|
||||
{
|
||||
if (id % transactionCommitRate == 0) {
|
||||
printDebugMessage(
|
||||
"Committing transactions " + to_string(id - transactionCommitRate + 1) + " - "
|
||||
+ to_string(id));
|
||||
"Committing transactions " + to_string(id - transactionCommitRate + 1) + " - "
|
||||
+ to_string(id));
|
||||
commitRecordedDataToDB();
|
||||
}
|
||||
}
|
||||
|
||||
void TlmRecorder::removeTransactionFromSystem(tlm::tlm_generic_payload& trans)
|
||||
void TlmRecorder::removeTransactionFromSystem(tlm::tlm_generic_payload &trans)
|
||||
{
|
||||
assert(currentTransactionsInSystem.count(&trans) != 0);
|
||||
|
||||
printDebugMessage("Removing transaction #" + to_string(currentTransactionsInSystem[&trans].id));
|
||||
printDebugMessage("Removing transaction #" + to_string(
|
||||
currentTransactionsInSystem[&trans].id));
|
||||
|
||||
Transaction& recordingData = currentTransactionsInSystem[&trans];
|
||||
Transaction &recordingData = currentTransactionsInSystem[&trans];
|
||||
recordedData.push_back(recordingData);
|
||||
currentTransactionsInSystem.erase(&trans);
|
||||
}
|
||||
@@ -185,18 +179,17 @@ void TlmRecorder::removeTransactionFromSystem(tlm::tlm_generic_payload& trans)
|
||||
void TlmRecorder::commitRecordedDataToDB()
|
||||
{
|
||||
sqlite3_exec(db, "BEGIN;", 0, 0, 0);
|
||||
for(Transaction& recordingData: recordedData)
|
||||
{
|
||||
for (Transaction &recordingData : recordedData) {
|
||||
assert(recordingData.recordedPhases.size() > 0);
|
||||
insertTransactionInDB(recordingData);
|
||||
for(Transaction::Phase& phaseData: recordingData.recordedPhases)
|
||||
{
|
||||
insertPhaseInDB(phaseData.name,phaseData.interval.start,phaseData.interval.end,recordingData.id);
|
||||
for (Transaction::Phase &phaseData : recordingData.recordedPhases) {
|
||||
insertPhaseInDB(phaseData.name, phaseData.interval.start,
|
||||
phaseData.interval.end, recordingData.id);
|
||||
}
|
||||
|
||||
sc_time rangeBegin = recordingData.recordedPhases.front().interval.start;
|
||||
sc_time rangeEnd = recordingData.recordedPhases.back().interval.end;
|
||||
insertRangeInDB(recordingData.id,rangeBegin,rangeEnd);
|
||||
insertRangeInDB(recordingData.id, rangeBegin, rangeEnd);
|
||||
}
|
||||
|
||||
sqlite3_exec(db, "COMMIT;", 0, 0, 0);
|
||||
@@ -206,7 +199,7 @@ void TlmRecorder::commitRecordedDataToDB()
|
||||
|
||||
void TlmRecorder::Transaction::insertPhase(string name, sc_time begin)
|
||||
{
|
||||
recordedPhases.push_back(Phase(name,begin));
|
||||
recordedPhases.push_back(Phase(name, begin));
|
||||
}
|
||||
|
||||
void TlmRecorder::Transaction::setPhaseEnd(string name, sc_time end)
|
||||
@@ -214,32 +207,28 @@ void TlmRecorder::Transaction::setPhaseEnd(string name, sc_time end)
|
||||
// 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)
|
||||
{
|
||||
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");
|
||||
SC_REPORT_FATAL("Recording Error",
|
||||
"While trying to set phase end: phaseBegin has not been recorded");
|
||||
}
|
||||
|
||||
void TlmRecorder::openDB(std::string name)
|
||||
{
|
||||
ifstream f(name.c_str());
|
||||
if(f.good())
|
||||
{
|
||||
if(remove(name.c_str()) != 0)
|
||||
{
|
||||
SC_REPORT_FATAL("TlmRecorder", "Error deleting file" );
|
||||
if (f.good()) {
|
||||
if (remove(name.c_str()) != 0) {
|
||||
SC_REPORT_FATAL("TlmRecorder", "Error deleting file" );
|
||||
}
|
||||
}
|
||||
|
||||
if (sqlite3_open(name.c_str(), &db) != SQLITE_OK)
|
||||
{
|
||||
if (sqlite3_open(name.c_str(), &db) != SQLITE_OK) {
|
||||
SC_REPORT_FATAL("Error in TraceRecorder", "Error cannot open database");
|
||||
sqlite3_close(db);
|
||||
}
|
||||
@@ -257,117 +246,152 @@ void TlmRecorder::setUpTransactionTerminatingPhases()
|
||||
transactionTerminatingPhases.push_back(tlm::END_RESP);
|
||||
|
||||
// Refresh All
|
||||
transactionTerminatingPhases.push_back(static_cast<const tlm::tlm_phase>(END_REFA));
|
||||
transactionTerminatingPhases.push_back(static_cast<const tlm::tlm_phase>
|
||||
(END_REFA));
|
||||
|
||||
// Refresh Bank
|
||||
transactionTerminatingPhases.push_back(static_cast<const tlm::tlm_phase>(END_REFB));
|
||||
transactionTerminatingPhases.push_back(static_cast<const tlm::tlm_phase>
|
||||
(END_REFB));
|
||||
|
||||
// Phases for Power Down
|
||||
transactionTerminatingPhases.push_back(static_cast<const tlm::tlm_phase>(END_PDNA));
|
||||
transactionTerminatingPhases.push_back(static_cast<const tlm::tlm_phase>(END_PDNP));
|
||||
transactionTerminatingPhases.push_back(static_cast<const tlm::tlm_phase>(END_SREF));
|
||||
transactionTerminatingPhases.push_back(static_cast<const tlm::tlm_phase>
|
||||
(END_PDNA));
|
||||
transactionTerminatingPhases.push_back(static_cast<const tlm::tlm_phase>
|
||||
(END_PDNP));
|
||||
transactionTerminatingPhases.push_back(static_cast<const tlm::tlm_phase>
|
||||
(END_SREF));
|
||||
|
||||
// Phases for Power Down Bankwise
|
||||
transactionTerminatingPhases.push_back(static_cast<const tlm::tlm_phase>(END_PDNAB));
|
||||
transactionTerminatingPhases.push_back(static_cast<const tlm::tlm_phase>(END_PDNPB));
|
||||
transactionTerminatingPhases.push_back(static_cast<const tlm::tlm_phase>(END_SREFB));
|
||||
transactionTerminatingPhases.push_back(static_cast<const tlm::tlm_phase>
|
||||
(END_PDNAB));
|
||||
transactionTerminatingPhases.push_back(static_cast<const tlm::tlm_phase>
|
||||
(END_PDNPB));
|
||||
transactionTerminatingPhases.push_back(static_cast<const tlm::tlm_phase>
|
||||
(END_SREFB));
|
||||
}
|
||||
|
||||
void TlmRecorder::prepareSqlStatements()
|
||||
{
|
||||
insertTransactionString =
|
||||
"INSERT INTO Transactions VALUES (:id,:rangeID,:address,:burstlength,:thread,:channel,:bank,:bankgroup,:row,:column,:dataStrobeBegin,:dataStrobeEnd, :timeOfGeneration,:command)";
|
||||
"INSERT INTO Transactions VALUES (:id,:rangeID,:address,:burstlength,:thread,:channel,:bank,:bankgroup,:row,:column,:dataStrobeBegin,:dataStrobeEnd, :timeOfGeneration,:command)";
|
||||
insertRangeString = "INSERT INTO Ranges VALUES (:id,:begin,:end)";
|
||||
updateRangeString = "UPDATE Ranges SET End = :end WHERE ID = :id";
|
||||
updateDataStrobeString = "UPDATE Transactions SET DataStrobeBegin = :begin, DataStrobeEnd = :end WHERE ID = :id";
|
||||
updateDataStrobeString =
|
||||
"UPDATE Transactions SET DataStrobeBegin = :begin, DataStrobeEnd = :end WHERE ID = :id";
|
||||
|
||||
insertPhaseString =
|
||||
"INSERT INTO Phases (PhaseName,PhaseBegin,PhaseEnd,Transact) VALUES (:name,:begin,:end,:transaction)";
|
||||
"INSERT INTO Phases (PhaseName,PhaseBegin,PhaseEnd,Transact) VALUES (:name,:begin,:end,:transaction)";
|
||||
updatePhaseString =
|
||||
"UPDATE Phases SET PhaseEnd = :end WHERE Transact = :trans AND PhaseName = :name";
|
||||
"UPDATE Phases SET PhaseEnd = :end WHERE Transact = :trans AND PhaseName = :name";
|
||||
insertGeneralInfoString =
|
||||
"INSERT INTO GeneralInfo (NumberOfTransactions,TraceEnd,NumberOfBanks,clk,UnitOfTime,MCconfig,Memspec,Traces, WindowSize, FlexibleRefresh, MaxRefBurst, ControllerThread) VALUES"
|
||||
"(:numberOfTransactions,:end,:numberOfBanks,:clk,:unitOfTime,:mcconfig,:memspec,:traces,:windowSize, :flexibleRefresh, :maxRefBurst, :controllerThread)";
|
||||
insertDebugMessageString = "INSERT INTO DebugMessages (Time,Message) Values (:time,:message)";
|
||||
"INSERT INTO GeneralInfo (NumberOfTransactions,TraceEnd,NumberOfBanks,clk,UnitOfTime,MCconfig,Memspec,Traces, WindowSize, FlexibleRefresh, MaxRefBurst, ControllerThread) VALUES"
|
||||
"(:numberOfTransactions,:end,:numberOfBanks,:clk,:unitOfTime,:mcconfig,:memspec,:traces,:windowSize, :flexibleRefresh, :maxRefBurst, :controllerThread)";
|
||||
insertDebugMessageString =
|
||||
"INSERT INTO DebugMessages (Time,Message) Values (:time,:message)";
|
||||
insertPowerString = "INSERT INTO Power VALUES (:time,:averagePower)";
|
||||
|
||||
sqlite3_prepare_v2(db, insertTransactionString.c_str(), -1, &insertTransactionStatement, 0);
|
||||
sqlite3_prepare_v2(db, insertTransactionString.c_str(), -1,
|
||||
&insertTransactionStatement, 0);
|
||||
sqlite3_prepare_v2(db, insertRangeString.c_str(), -1, &insertRangeStatement, 0);
|
||||
sqlite3_prepare_v2(db, updateRangeString.c_str(), -1, &updateRangeStatement, 0);
|
||||
sqlite3_prepare_v2(db, insertPhaseString.c_str(), -1, &insertPhaseStatement, 0);
|
||||
sqlite3_prepare_v2(db, updatePhaseString.c_str(), -1, &updatePhaseStatement, 0);
|
||||
sqlite3_prepare_v2(db, updateDataStrobeString.c_str(), -1, &updateDataStrobeStatement, 0);
|
||||
sqlite3_prepare_v2(db, insertGeneralInfoString.c_str(), -1, &insertGeneralInfoStatement, 0);
|
||||
sqlite3_prepare_v2(db, insertDebugMessageString.c_str(), -1, &insertDebugMessageStatement, 0);
|
||||
sqlite3_prepare_v2(db, updateDataStrobeString.c_str(), -1,
|
||||
&updateDataStrobeStatement, 0);
|
||||
sqlite3_prepare_v2(db, insertGeneralInfoString.c_str(), -1,
|
||||
&insertGeneralInfoStatement, 0);
|
||||
sqlite3_prepare_v2(db, insertDebugMessageString.c_str(), -1,
|
||||
&insertDebugMessageStatement, 0);
|
||||
sqlite3_prepare_v2(db, insertPowerString.c_str(), -1, &insertPowerStatement, 0);
|
||||
}
|
||||
|
||||
void TlmRecorder::insertDebugMessageInDB(string message, const sc_time& time)
|
||||
void TlmRecorder::insertDebugMessageInDB(string message, const sc_time &time)
|
||||
{
|
||||
sqlite3_bind_int64(insertDebugMessageStatement, 1, time.value());
|
||||
sqlite3_bind_text(insertDebugMessageStatement, 2, message.c_str(), message.length(), 0);
|
||||
sqlite3_bind_text(insertDebugMessageStatement, 2, message.c_str(),
|
||||
message.length(), 0);
|
||||
executeSqlStatement(insertDebugMessageStatement);
|
||||
}
|
||||
|
||||
void TlmRecorder::insertGeneralInfo()
|
||||
{
|
||||
sqlite3_bind_int64(insertGeneralInfoStatement, 1, totalNumTransactions - 1);
|
||||
sqlite3_bind_int64(insertGeneralInfoStatement, 2, simulationTimeCoveredByRecording.value());
|
||||
sqlite3_bind_int64(insertGeneralInfoStatement, 2,
|
||||
simulationTimeCoveredByRecording.value());
|
||||
sqlite3_bind_int(insertGeneralInfoStatement, 3,
|
||||
Configuration::getInstance().memSpec.NumberOfBanks);
|
||||
sqlite3_bind_int(insertGeneralInfoStatement, 4, Configuration::getInstance().memSpec.clk.value());
|
||||
sqlite3_bind_int(insertGeneralInfoStatement, 4,
|
||||
Configuration::getInstance().memSpec.clk.value());
|
||||
sqlite3_bind_text(insertGeneralInfoStatement, 5, "PS", 2, NULL);
|
||||
sqlite3_bind_text(insertGeneralInfoStatement, 6, mcconfig.c_str(), mcconfig.length(), NULL);
|
||||
sqlite3_bind_text(insertGeneralInfoStatement, 7, memspec.c_str(), memspec.length(), NULL);
|
||||
sqlite3_bind_text(insertGeneralInfoStatement, 8, traces.c_str(), traces.length(), NULL);
|
||||
sqlite3_bind_text(insertGeneralInfoStatement, 6, mcconfig.c_str(),
|
||||
mcconfig.length(), NULL);
|
||||
sqlite3_bind_text(insertGeneralInfoStatement, 7, memspec.c_str(),
|
||||
memspec.length(), NULL);
|
||||
sqlite3_bind_text(insertGeneralInfoStatement, 8, traces.c_str(),
|
||||
traces.length(), NULL);
|
||||
if (!Configuration::getInstance().EnableWindowing)
|
||||
sqlite3_bind_int64(insertGeneralInfoStatement, 9, 0);
|
||||
else
|
||||
sqlite3_bind_int64(insertGeneralInfoStatement, 9, (Configuration::getInstance().memSpec.clk*Configuration::getInstance().WindowSize).value());
|
||||
if (Configuration::getInstance().ControllerCoreEnableRefPostpone || Configuration::getInstance().ControllerCoreEnableRefPullIn)
|
||||
{
|
||||
sqlite3_bind_int(insertGeneralInfoStatement, 10, 1);
|
||||
sqlite3_bind_int(insertGeneralInfoStatement, 11, std::max(Configuration::getInstance().ControllerCoreMaxPulledInARCmd, Configuration::getInstance().ControllerCoreMaxPostponedARCmd));
|
||||
sqlite3_bind_int64(insertGeneralInfoStatement, 9,
|
||||
(Configuration::getInstance().memSpec.clk *
|
||||
Configuration::getInstance().WindowSize).value());
|
||||
if (Configuration::getInstance().ControllerCoreEnableRefPostpone
|
||||
|| Configuration::getInstance().ControllerCoreEnableRefPullIn) {
|
||||
sqlite3_bind_int(insertGeneralInfoStatement, 10, 1);
|
||||
sqlite3_bind_int(insertGeneralInfoStatement, 11,
|
||||
std::max(Configuration::getInstance().ControllerCoreMaxPulledInARCmd,
|
||||
Configuration::getInstance().ControllerCoreMaxPostponedARCmd));
|
||||
} else {
|
||||
sqlite3_bind_int(insertGeneralInfoStatement, 10, 0);
|
||||
sqlite3_bind_int(insertGeneralInfoStatement, 11, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
sqlite3_bind_int(insertGeneralInfoStatement, 10, 0);
|
||||
sqlite3_bind_int(insertGeneralInfoStatement, 11, 0);
|
||||
}
|
||||
sqlite3_bind_int(insertGeneralInfoStatement, 12, Controller::ControllerThreadId()); ;
|
||||
sqlite3_bind_int(insertGeneralInfoStatement, 12,
|
||||
Controller::ControllerThreadId()); ;
|
||||
executeSqlStatement(insertGeneralInfoStatement);
|
||||
}
|
||||
|
||||
void TlmRecorder::insertTransactionInDB(Transaction& recordingData)
|
||||
void TlmRecorder::insertTransactionInDB(Transaction &recordingData)
|
||||
{
|
||||
sqlite3_bind_int(insertTransactionStatement, 1, recordingData.id);
|
||||
sqlite3_bind_int(insertTransactionStatement, 2, recordingData.id);
|
||||
sqlite3_bind_int(insertTransactionStatement, 3, recordingData.address);
|
||||
sqlite3_bind_int(insertTransactionStatement, 4, recordingData.burstlength);
|
||||
sqlite3_bind_int(insertTransactionStatement, 5, recordingData.dramExtension.getThread().ID());
|
||||
sqlite3_bind_int(insertTransactionStatement, 6, recordingData.dramExtension.getChannel().ID());
|
||||
sqlite3_bind_int(insertTransactionStatement, 7, recordingData.dramExtension.getBank().ID());
|
||||
sqlite3_bind_int(insertTransactionStatement, 8, recordingData.dramExtension.getBankGroup().ID());
|
||||
sqlite3_bind_int(insertTransactionStatement, 9, recordingData.dramExtension.getRow().ID());
|
||||
sqlite3_bind_int(insertTransactionStatement, 10, recordingData.dramExtension.getColumn().ID());
|
||||
sqlite3_bind_int64(insertTransactionStatement, 11, recordingData.timeOnDataStrobe.start.value());
|
||||
sqlite3_bind_int64(insertTransactionStatement, 12, recordingData.timeOnDataStrobe.end.value());
|
||||
sqlite3_bind_int64(insertTransactionStatement, 13, recordingData.timeOfGeneration.value());
|
||||
sqlite3_bind_int(insertTransactionStatement, 5,
|
||||
recordingData.dramExtension.getThread().ID());
|
||||
sqlite3_bind_int(insertTransactionStatement, 6,
|
||||
recordingData.dramExtension.getChannel().ID());
|
||||
sqlite3_bind_int(insertTransactionStatement, 7,
|
||||
recordingData.dramExtension.getBank().ID());
|
||||
sqlite3_bind_int(insertTransactionStatement, 8,
|
||||
recordingData.dramExtension.getBankGroup().ID());
|
||||
sqlite3_bind_int(insertTransactionStatement, 9,
|
||||
recordingData.dramExtension.getRow().ID());
|
||||
sqlite3_bind_int(insertTransactionStatement, 10,
|
||||
recordingData.dramExtension.getColumn().ID());
|
||||
sqlite3_bind_int64(insertTransactionStatement, 11,
|
||||
recordingData.timeOnDataStrobe.start.value());
|
||||
sqlite3_bind_int64(insertTransactionStatement, 12,
|
||||
recordingData.timeOnDataStrobe.end.value());
|
||||
sqlite3_bind_int64(insertTransactionStatement, 13,
|
||||
recordingData.timeOfGeneration.value());
|
||||
|
||||
executeSqlStatement(insertTransactionStatement);
|
||||
}
|
||||
|
||||
void TlmRecorder::insertRangeInDB(unsigned int id, const sc_time& begin, const sc_time& end)
|
||||
void TlmRecorder::insertRangeInDB(unsigned int id, const sc_time &begin,
|
||||
const sc_time &end)
|
||||
{
|
||||
sqlite3_bind_int(insertRangeStatement, 1, id);
|
||||
sqlite3_bind_int64(insertRangeStatement, 2, begin.value());
|
||||
sqlite3_bind_int64(insertRangeStatement, 3, end.value());
|
||||
executeSqlStatement(insertRangeStatement);
|
||||
}
|
||||
void TlmRecorder::insertPhaseInDB(string phaseName, const sc_time& begin, const sc_time& end,
|
||||
void TlmRecorder::insertPhaseInDB(string phaseName, const sc_time &begin,
|
||||
const sc_time &end,
|
||||
unsigned int transactionID)
|
||||
{
|
||||
sqlite3_bind_text(insertPhaseStatement, 1, phaseName.c_str(), phaseName.length(), 0);
|
||||
sqlite3_bind_text(insertPhaseStatement, 1, phaseName.c_str(),
|
||||
phaseName.length(), 0);
|
||||
sqlite3_bind_int64(insertPhaseStatement, 2, begin.value());
|
||||
sqlite3_bind_int64(insertPhaseStatement, 3, end.value());
|
||||
sqlite3_bind_int(insertPhaseStatement, 4, transactionID);
|
||||
@@ -375,12 +399,12 @@ void TlmRecorder::insertPhaseInDB(string phaseName, const sc_time& begin, const
|
||||
}
|
||||
|
||||
|
||||
void TlmRecorder::executeSqlStatement(sqlite3_stmt* statement)
|
||||
void TlmRecorder::executeSqlStatement(sqlite3_stmt *statement)
|
||||
{
|
||||
int errorCode = sqlite3_step(statement);
|
||||
if (errorCode != SQLITE_DONE)
|
||||
{
|
||||
reportFatal("Error in TraceRecorder", string("Could not execute statement. Error code: ") + to_string(errorCode));
|
||||
if (errorCode != SQLITE_DONE) {
|
||||
reportFatal("Error in TraceRecorder",
|
||||
string("Could not execute statement. Error code: ") + to_string(errorCode));
|
||||
}
|
||||
sqlite3_reset(statement);
|
||||
}
|
||||
@@ -389,10 +413,9 @@ void TlmRecorder::executeSqlCommand(string command)
|
||||
{
|
||||
printDebugMessage("Creating database by running provided sql script");
|
||||
|
||||
char * errMsg = 0;
|
||||
char *errMsg = 0;
|
||||
int rc = sqlite3_exec(db, command.c_str(), NULL, 0, &errMsg);
|
||||
if (rc != SQLITE_OK)
|
||||
{
|
||||
if (rc != SQLITE_OK) {
|
||||
SC_REPORT_FATAL("SQLITE Error", errMsg);
|
||||
sqlite3_free(errMsg);
|
||||
}
|
||||
@@ -407,13 +430,22 @@ void TlmRecorder::printDebugMessage(std::string message)
|
||||
|
||||
void TlmRecorder::closeConnection()
|
||||
{
|
||||
if(TlmRecorder::recordingEnabled)
|
||||
{
|
||||
if (TlmRecorder::recordingEnabled) {
|
||||
commitRecordedDataToDB();
|
||||
insertGeneralInfo();
|
||||
printDebugMessage(
|
||||
"Number of transactions written to DB: " + std::to_string(totalNumTransactions - 1));
|
||||
"Number of transactions written to DB: " + std::to_string(
|
||||
totalNumTransactions - 1));
|
||||
printDebugMessage("tlmPhaseRecorder:\tEnd Recording");
|
||||
sqlite3_finalize(insertTransactionStatement);
|
||||
sqlite3_finalize(insertRangeStatement);
|
||||
sqlite3_finalize(updateRangeStatement);
|
||||
sqlite3_finalize(insertPhaseStatement);
|
||||
sqlite3_finalize(updatePhaseStatement);
|
||||
sqlite3_finalize(insertGeneralInfoStatement);
|
||||
sqlite3_finalize(insertDebugMessageStatement);
|
||||
sqlite3_finalize(updateDataStrobeStatement);
|
||||
sqlite3_finalize(insertPowerStatement);
|
||||
sqlite3_close(db);
|
||||
db = NULL;
|
||||
}
|
||||
|
||||
@@ -55,7 +55,8 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
class TlmRecorder : public sc_module {
|
||||
class TlmRecorder : public sc_module
|
||||
{
|
||||
public:
|
||||
std::string sqlScriptURI;
|
||||
std::string dbName;
|
||||
@@ -64,22 +65,32 @@ public:
|
||||
TlmRecorder(sc_module_name /*name*/, string uri, string dbname, bool recenable);
|
||||
~TlmRecorder();
|
||||
|
||||
void recordMCconfig(string mcconfig){this->mcconfig = mcconfig;}
|
||||
void recordMemspec(string memspec){this->memspec = memspec;}
|
||||
void recordTracenames(string traces){this->traces = traces;}
|
||||
void recordMCconfig(string mcconfig)
|
||||
{
|
||||
this->mcconfig = mcconfig;
|
||||
}
|
||||
void recordMemspec(string memspec)
|
||||
{
|
||||
this->memspec = memspec;
|
||||
}
|
||||
void recordTracenames(string traces)
|
||||
{
|
||||
this->traces = traces;
|
||||
}
|
||||
|
||||
void recordPhase(tlm::tlm_generic_payload &trans, tlm::tlm_phase phase, sc_time time);
|
||||
void recordPhase(tlm::tlm_generic_payload &trans, tlm::tlm_phase phase,
|
||||
sc_time time);
|
||||
void recordPower(double timeInSeconds, double averagePower);
|
||||
void recordDebugMessage(std::string message, sc_time time);
|
||||
void updateDataStrobe(const sc_time& begin, const sc_time& end, tlm::tlm_generic_payload& trans);
|
||||
void updateDataStrobe(const sc_time &begin, const sc_time &end,
|
||||
tlm::tlm_generic_payload &trans);
|
||||
void closeConnection();
|
||||
|
||||
private:
|
||||
|
||||
struct Transaction
|
||||
{
|
||||
Transaction(){}
|
||||
Transaction(unsigned int id):id(id){}
|
||||
struct Transaction {
|
||||
Transaction() {}
|
||||
Transaction(unsigned int id): id(id) {}
|
||||
|
||||
unsigned int id;
|
||||
unsigned int address;
|
||||
@@ -88,53 +99,56 @@ private:
|
||||
sc_time timeOfGeneration;
|
||||
TimeInterval timeOnDataStrobe;
|
||||
|
||||
struct Phase
|
||||
{
|
||||
Phase(string name,sc_time begin): name(name), interval(begin,SC_ZERO_TIME){}
|
||||
struct Phase {
|
||||
Phase(string name, sc_time begin): name(name), interval(begin, SC_ZERO_TIME) {}
|
||||
string name;
|
||||
TimeInterval interval;
|
||||
};
|
||||
std::vector<Phase> recordedPhases;
|
||||
|
||||
void insertPhase(string name,sc_time begin);
|
||||
void setPhaseEnd(string name,sc_time end);
|
||||
void insertPhase(string name, sc_time begin);
|
||||
void setPhaseEnd(string name, sc_time end);
|
||||
};
|
||||
|
||||
std::string mcconfig,memspec,traces;
|
||||
std::string mcconfig, memspec, traces;
|
||||
|
||||
void prepareSqlStatements();
|
||||
void executeSqlCommand(std::string command);
|
||||
void executeSqlStatement(sqlite3_stmt* statement);
|
||||
void executeSqlStatement(sqlite3_stmt *statement);
|
||||
|
||||
void openDB(std::string name);
|
||||
void createTables(std::string pathToURI);
|
||||
void setUpTransactionTerminatingPhases();
|
||||
|
||||
void introduceTransactionSystem(tlm::tlm_generic_payload& trans);
|
||||
void removeTransactionFromSystem(tlm::tlm_generic_payload& trans);
|
||||
void introduceTransactionSystem(tlm::tlm_generic_payload &trans);
|
||||
void removeTransactionFromSystem(tlm::tlm_generic_payload &trans);
|
||||
|
||||
void commitRecordedDataToDB();
|
||||
void insertGeneralInfo();
|
||||
void insertTransactionInDB(Transaction& recordingData);
|
||||
void insertRangeInDB(unsigned int id, const sc_time& begin, const sc_time& end);
|
||||
void insertPhaseInDB(string phaseName, const sc_time& begin, const sc_time& end, unsigned int transactionID);
|
||||
void insertDebugMessageInDB(string message, const sc_time& time);
|
||||
void insertTransactionInDB(Transaction &recordingData);
|
||||
void insertRangeInDB(unsigned int id, const sc_time &begin, const sc_time &end);
|
||||
void insertPhaseInDB(string phaseName, const sc_time &begin, const sc_time &end,
|
||||
unsigned int transactionID);
|
||||
void insertDebugMessageInDB(string message, const sc_time &time);
|
||||
|
||||
void printDebugMessage(std::string message);
|
||||
|
||||
static const int transactionCommitRate = 1000;
|
||||
vector<Transaction> recordedData;
|
||||
map<tlm::tlm_generic_payload*, Transaction> currentTransactionsInSystem;
|
||||
map<tlm::tlm_generic_payload *, Transaction> currentTransactionsInSystem;
|
||||
|
||||
unsigned int totalNumTransactions;
|
||||
sc_time simulationTimeCoveredByRecording;
|
||||
|
||||
std::vector<tlm::tlm_phase> transactionTerminatingPhases;
|
||||
sqlite3 *db = NULL;
|
||||
sqlite3_stmt *insertTransactionStatement, *insertRangeStatement, *updateRangeStatement,
|
||||
*insertPhaseStatement, *updatePhaseStatement, *insertGeneralInfoStatement, *insertDebugMessageStatement, *updateDataStrobeStatement, *insertPowerStatement;
|
||||
std::string insertTransactionString, insertRangeString, updateRangeString, insertPhaseString, updatePhaseString, insertGeneralInfoString,
|
||||
insertDebugMessageString, updateDataStrobeString, insertPowerString;
|
||||
sqlite3_stmt *insertTransactionStatement, *insertRangeStatement,
|
||||
*updateRangeStatement,
|
||||
*insertPhaseStatement, *updatePhaseStatement, *insertGeneralInfoStatement,
|
||||
*insertDebugMessageStatement, *updateDataStrobeStatement, *insertPowerStatement;
|
||||
std::string insertTransactionString, insertRangeString, updateRangeString,
|
||||
insertPhaseString, updatePhaseString, insertGeneralInfoString,
|
||||
insertDebugMessageString, updateDataStrobeString, insertPowerString;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -52,7 +52,8 @@ bool TimeInterval::timeIsInInterval(sc_time time)
|
||||
|
||||
bool TimeInterval::intersects(TimeInterval other)
|
||||
{
|
||||
return other.timeIsInInterval(this->start) || this->timeIsInInterval(other.start);
|
||||
return other.timeIsInInterval(this->start)
|
||||
|| this->timeIsInInterval(other.start);
|
||||
}
|
||||
|
||||
sc_time getDistance(sc_time a, sc_time b)
|
||||
@@ -76,17 +77,16 @@ std::string phaseNameToString(tlm::tlm_phase phase)
|
||||
return str;
|
||||
}
|
||||
|
||||
unsigned int queryUIntParameter(XMLElement* node, string name)
|
||||
unsigned int queryUIntParameter(XMLElement *node, string name)
|
||||
{
|
||||
int result = 0;
|
||||
XMLElement* element;
|
||||
XMLElement *element;
|
||||
for (element = node->FirstChildElement("parameter"); element != NULL;
|
||||
element = element->NextSiblingElement("parameter"))
|
||||
{
|
||||
if (element->Attribute("id") == name)
|
||||
{
|
||||
element = element->NextSiblingElement("parameter")) {
|
||||
if (element->Attribute("id") == name) {
|
||||
sc_assert(!strcmp(element->Attribute("type"), "uint"));
|
||||
XMLError __attribute__((unused)) error = element->QueryIntAttribute("value", &result);
|
||||
XMLError __attribute__((unused)) error = element->QueryIntAttribute("value",
|
||||
&result);
|
||||
sc_assert(!error);
|
||||
return result;
|
||||
}
|
||||
@@ -96,31 +96,28 @@ unsigned int queryUIntParameter(XMLElement* node, string name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool parameterExists(tinyxml2::XMLElement* node, std::string name)
|
||||
bool parameterExists(tinyxml2::XMLElement *node, std::string name)
|
||||
{
|
||||
XMLElement* element;
|
||||
XMLElement *element;
|
||||
for (element = node->FirstChildElement("parameter"); element != NULL;
|
||||
element = element->NextSiblingElement("parameter"))
|
||||
{
|
||||
if (element->Attribute("id") == name)
|
||||
{
|
||||
element = element->NextSiblingElement("parameter")) {
|
||||
if (element->Attribute("id") == name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
double queryDoubleParameter(XMLElement* node, string name)
|
||||
double queryDoubleParameter(XMLElement *node, string name)
|
||||
{
|
||||
double result = 0;
|
||||
XMLElement* element;
|
||||
XMLElement *element;
|
||||
for (element = node->FirstChildElement("parameter"); element != NULL;
|
||||
element = element->NextSiblingElement("parameter"))
|
||||
{
|
||||
if (element->Attribute("id") == name)
|
||||
{
|
||||
element = element->NextSiblingElement("parameter")) {
|
||||
if (element->Attribute("id") == name) {
|
||||
sc_assert(!strcmp(element->Attribute("type"), "double"));
|
||||
XMLError __attribute__((unused)) error = element->QueryDoubleAttribute("value", &result);
|
||||
XMLError __attribute__((unused)) error = element->QueryDoubleAttribute("value",
|
||||
&result);
|
||||
sc_assert(!error);
|
||||
return result;
|
||||
}
|
||||
@@ -130,17 +127,16 @@ double queryDoubleParameter(XMLElement* node, string name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool queryBoolParameter(XMLElement* node, string name)
|
||||
bool queryBoolParameter(XMLElement *node, string name)
|
||||
{
|
||||
bool result = false;
|
||||
XMLElement* element;// = node->FirstChildElement("parameter");
|
||||
XMLElement *element;// = node->FirstChildElement("parameter");
|
||||
for (element = node->FirstChildElement("parameter"); element != NULL;
|
||||
element = element->NextSiblingElement("parameter"))
|
||||
{
|
||||
if (element->Attribute("id") == name)
|
||||
{
|
||||
element = element->NextSiblingElement("parameter")) {
|
||||
if (element->Attribute("id") == name) {
|
||||
sc_assert(!strcmp(element->Attribute("type"), "bool"));
|
||||
XMLError __attribute__((unused)) error = element->QueryBoolAttribute("value", &result);
|
||||
XMLError __attribute__((unused)) error = element->QueryBoolAttribute("value",
|
||||
&result);
|
||||
sc_assert(!error);
|
||||
return result;
|
||||
}
|
||||
@@ -150,14 +146,12 @@ bool queryBoolParameter(XMLElement* node, string name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
string queryStringParameter(XMLElement* node, string name)
|
||||
string queryStringParameter(XMLElement *node, string name)
|
||||
{
|
||||
XMLElement* element;
|
||||
XMLElement *element;
|
||||
for (element = node->FirstChildElement("parameter"); element != NULL;
|
||||
element = element->NextSiblingElement("parameter"))
|
||||
{
|
||||
if (element->Attribute("id") == name)
|
||||
{
|
||||
element = element->NextSiblingElement("parameter")) {
|
||||
if (element->Attribute("id") == name) {
|
||||
return element->Attribute("value");
|
||||
}
|
||||
}
|
||||
@@ -168,36 +162,57 @@ string queryStringParameter(XMLElement* node, string name)
|
||||
|
||||
string errorToString(XMLError error)
|
||||
{
|
||||
switch(error){
|
||||
case XML_NO_ERROR: return "no error"; case XML_NO_ATTRIBUTE: return "NO_ATTRIBUTE";
|
||||
case XML_WRONG_ATTRIBUTE_TYPE: return "WRONG_ATTRIBUTE_TYPE";
|
||||
case XML_ERROR_FILE_NOT_FOUND: return "FILE_NOT_FOUND";
|
||||
case XML_ERROR_FILE_COULD_NOT_BE_OPENED: return "FILE_COULD_NOT_BE_OPENED";
|
||||
case XML_ERROR_FILE_READ_ERROR: return "FILE_READ_ERROR";
|
||||
case XML_ERROR_ELEMENT_MISMATCH: return "ERROR_ELEMENT_MISMATCH";
|
||||
case XML_ERROR_PARSING_ELEMENT: return "ERROR_PARSING_ELEMENT";
|
||||
case XML_ERROR_PARSING_ATTRIBUTE: return "ERROR_PARSING_ATTRIBUTE";
|
||||
case XML_ERROR_IDENTIFYING_TAG: return "ERROR_IDENTIFYING_TAG";
|
||||
case XML_ERROR_PARSING_TEXT: return "ERROR_PARSING_TEXT";
|
||||
case XML_ERROR_PARSING_CDATA: return "ERROR_PARSING_CDATA";
|
||||
case XML_ERROR_PARSING_COMMENT: return "ERROR_PARSING_COMMENT";
|
||||
case XML_ERROR_PARSING_DECLARATION: return "ERROR_PARSING_DECLARATION";
|
||||
case XML_ERROR_PARSING_UNKNOWN: return "ERROR_PARSING_UNKNOWN";
|
||||
case XML_ERROR_EMPTY_DOCUMENT: return "ERROR_EMPTY_DOCUMENT";
|
||||
case XML_ERROR_MISMATCHED_ELEMENT: return "ERROR_MISMATCHED_ELEMENT";
|
||||
case XML_ERROR_PARSING: return "ERROR_PARSING";
|
||||
case XML_CAN_NOT_CONVERT_TEXT: return "CAN_NOT_CONVERT_TEXT";
|
||||
case XML_NO_TEXT_NODE: return "NO_TEXT_NODE";
|
||||
default: return "";
|
||||
switch (error) {
|
||||
case XML_NO_ERROR:
|
||||
return "no error";
|
||||
case XML_NO_ATTRIBUTE:
|
||||
return "NO_ATTRIBUTE";
|
||||
case XML_WRONG_ATTRIBUTE_TYPE:
|
||||
return "WRONG_ATTRIBUTE_TYPE";
|
||||
case XML_ERROR_FILE_NOT_FOUND:
|
||||
return "FILE_NOT_FOUND";
|
||||
case XML_ERROR_FILE_COULD_NOT_BE_OPENED:
|
||||
return "FILE_COULD_NOT_BE_OPENED";
|
||||
case XML_ERROR_FILE_READ_ERROR:
|
||||
return "FILE_READ_ERROR";
|
||||
case XML_ERROR_ELEMENT_MISMATCH:
|
||||
return "ERROR_ELEMENT_MISMATCH";
|
||||
case XML_ERROR_PARSING_ELEMENT:
|
||||
return "ERROR_PARSING_ELEMENT";
|
||||
case XML_ERROR_PARSING_ATTRIBUTE:
|
||||
return "ERROR_PARSING_ATTRIBUTE";
|
||||
case XML_ERROR_IDENTIFYING_TAG:
|
||||
return "ERROR_IDENTIFYING_TAG";
|
||||
case XML_ERROR_PARSING_TEXT:
|
||||
return "ERROR_PARSING_TEXT";
|
||||
case XML_ERROR_PARSING_CDATA:
|
||||
return "ERROR_PARSING_CDATA";
|
||||
case XML_ERROR_PARSING_COMMENT:
|
||||
return "ERROR_PARSING_COMMENT";
|
||||
case XML_ERROR_PARSING_DECLARATION:
|
||||
return "ERROR_PARSING_DECLARATION";
|
||||
case XML_ERROR_PARSING_UNKNOWN:
|
||||
return "ERROR_PARSING_UNKNOWN";
|
||||
case XML_ERROR_EMPTY_DOCUMENT:
|
||||
return "ERROR_EMPTY_DOCUMENT";
|
||||
case XML_ERROR_MISMATCHED_ELEMENT:
|
||||
return "ERROR_MISMATCHED_ELEMENT";
|
||||
case XML_ERROR_PARSING:
|
||||
return "ERROR_PARSING";
|
||||
case XML_CAN_NOT_CONVERT_TEXT:
|
||||
return "CAN_NOT_CONVERT_TEXT";
|
||||
case XML_NO_TEXT_NODE:
|
||||
return "NO_TEXT_NODE";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
void loadXML(string uri, XMLDocument& doc)
|
||||
void loadXML(string uri, XMLDocument &doc)
|
||||
{
|
||||
XMLError error = doc.LoadFile(uri.c_str());
|
||||
|
||||
if (error)
|
||||
{
|
||||
if (error) {
|
||||
reportFatal("Configuration", "Error loading xml from: " + uri + " "
|
||||
+ errorToString(error));
|
||||
}
|
||||
@@ -207,8 +222,7 @@ string loadTextFileContents(string filename)
|
||||
{
|
||||
|
||||
ifstream in(filename.c_str(), ios::in | ios::binary);
|
||||
if (in)
|
||||
{
|
||||
if (in) {
|
||||
string contents;
|
||||
in.seekg(0, ios::end);
|
||||
contents.resize(in.tellg());
|
||||
@@ -216,15 +230,13 @@ string loadTextFileContents(string filename)
|
||||
in.read(&contents[0], contents.size());
|
||||
in.close();
|
||||
return (contents);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
reportFatal("Error loading file", "Could not load textfile from " + filename);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
void setUpDummy(tlm::tlm_generic_payload& payload, Bank& bank)
|
||||
void setUpDummy(tlm::tlm_generic_payload &payload, Bank &bank)
|
||||
{
|
||||
payload.set_address(bank.getStartAddress());
|
||||
payload.set_command(tlm::TLM_READ_COMMAND);
|
||||
@@ -233,7 +245,9 @@ void setUpDummy(tlm::tlm_generic_payload& payload, Bank& bank)
|
||||
payload.set_dmi_allowed(false);
|
||||
payload.set_byte_enable_length(0);
|
||||
payload.set_streaming_width(0);
|
||||
payload.set_extension(new DramExtension(Thread(Controller::ControllerThreadId()), bank, BankGroup(0), Row(0), Column(0))); //payload takes ownership
|
||||
payload.set_extension(new DramExtension(Thread(
|
||||
Controller::ControllerThreadId()), bank, BankGroup(0), Row(0),
|
||||
Column(0))); //payload takes ownership
|
||||
//TODO .. Dummies muessen noch banggruppe und rank sauber bekommen .. noch was ueberlegen!!!
|
||||
}
|
||||
|
||||
@@ -242,15 +256,13 @@ std::string getFileName(std::string uri)
|
||||
// Remove directory if present.
|
||||
// Do this before extension removal incase directory has a period character.
|
||||
const size_t last_slash_idx = uri.find_last_of("\\/");
|
||||
if (std::string::npos != last_slash_idx)
|
||||
{
|
||||
if (std::string::npos != last_slash_idx) {
|
||||
uri.erase(0, last_slash_idx + 1);
|
||||
}
|
||||
|
||||
// Remove extension if present.
|
||||
const size_t period_idx = uri.rfind('.');
|
||||
if (std::string::npos != period_idx)
|
||||
{
|
||||
if (std::string::npos != period_idx) {
|
||||
uri.erase(period_idx);
|
||||
}
|
||||
return uri;
|
||||
|
||||
@@ -58,22 +58,23 @@ public: \
|
||||
//TODO : move to timing specific header
|
||||
sc_time getDistance(sc_time a, sc_time b);
|
||||
|
||||
struct TimeInterval
|
||||
{
|
||||
sc_time start,end;
|
||||
TimeInterval() : start(SC_ZERO_TIME), end(SC_ZERO_TIME){}
|
||||
TimeInterval(sc_time start,sc_time end) : start(start), end(end){}
|
||||
struct TimeInterval {
|
||||
sc_time start, end;
|
||||
TimeInterval() : start(SC_ZERO_TIME), end(SC_ZERO_TIME) {}
|
||||
TimeInterval(sc_time start, sc_time end) : start(start), end(end) {}
|
||||
|
||||
sc_time getLength() {return getDistance(start,end);}
|
||||
sc_time getLength()
|
||||
{
|
||||
return getDistance(start, end);
|
||||
}
|
||||
bool timeIsInInterval(sc_time time);
|
||||
bool intersects(TimeInterval other);
|
||||
};
|
||||
|
||||
template<typename Key, typename Val>
|
||||
inline Val getElementFromMap(const std::map<Key, Val>& m, Key key)
|
||||
inline Val getElementFromMap(const std::map<Key, Val> &m, Key key)
|
||||
{
|
||||
if (m.count(key) == 0)
|
||||
{
|
||||
if (m.count(key) == 0) {
|
||||
SC_REPORT_FATAL("Map", "Element not in map");
|
||||
}
|
||||
|
||||
@@ -81,17 +82,17 @@ inline Val getElementFromMap(const std::map<Key, Val>& m, Key key)
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool isIn(const T& value, const std::vector<T>& collection)
|
||||
bool isIn(const T &value, const std::vector<T> &collection)
|
||||
{
|
||||
for (T t : collection)
|
||||
{
|
||||
for (T t : collection) {
|
||||
if (t == value)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr const char headline[] = "=========================================================";
|
||||
constexpr const char headline[] =
|
||||
"=========================================================";
|
||||
|
||||
static inline void loadbar(unsigned int x,
|
||||
unsigned int n,
|
||||
@@ -108,24 +109,24 @@ static inline void loadbar(unsigned int x,
|
||||
for (unsigned int x = 0; x < c; x++)
|
||||
std::cout << "█";
|
||||
|
||||
if(rest >= 0 && rest < 0.125 && c != w)
|
||||
if (rest >= 0 && rest < 0.125 && c != w)
|
||||
std::cout << " ";
|
||||
if(rest >= 0.125 && rest < 2*0.125)
|
||||
if (rest >= 0.125 && rest < 2 * 0.125)
|
||||
std::cout << "▏";
|
||||
if(rest >= 2*0.125 && rest < 3*0.125)
|
||||
if (rest >= 2 * 0.125 && rest < 3 * 0.125)
|
||||
std::cout << "▎";
|
||||
if(rest >= 3*0.125 && rest < 4*0.125)
|
||||
if (rest >= 3 * 0.125 && rest < 4 * 0.125)
|
||||
std::cout << "▍";
|
||||
if(rest >= 4*0.125 && rest < 5*0.125)
|
||||
if (rest >= 4 * 0.125 && rest < 5 * 0.125)
|
||||
std::cout << "▌";
|
||||
if(rest >= 5*0.125 && rest < 6*0.125)
|
||||
if (rest >= 5 * 0.125 && rest < 6 * 0.125)
|
||||
std::cout << "▋";
|
||||
if(rest >= 6*0.125 && rest < 7*0.125)
|
||||
if (rest >= 6 * 0.125 && rest < 7 * 0.125)
|
||||
std::cout << "▊";
|
||||
if(rest >= 7*0.125 && rest < 8*0.125)
|
||||
if (rest >= 7 * 0.125 && rest < 8 * 0.125)
|
||||
std::cout << "▉";
|
||||
|
||||
for (unsigned int x = c; x < (w-1); x++)
|
||||
for (unsigned int x = c; x < (w - 1); x++)
|
||||
std::cout << " ";
|
||||
std::cout << "|\r" << std::flush;
|
||||
}
|
||||
@@ -137,15 +138,15 @@ std::string phaseNameToString(tlm::tlm_phase phase);
|
||||
|
||||
//TODO : Move to other source specific to xml
|
||||
std::string getFileName(std::string uri);
|
||||
bool parameterExists(tinyxml2::XMLElement* node, std::string name);
|
||||
bool parameterExists(tinyxml2::XMLElement *node, std::string name);
|
||||
std::string loadTextFileContents(std::string filename);
|
||||
void loadXML(std::string uri, tinyxml2::XMLDocument& doc);
|
||||
unsigned int queryUIntParameter(tinyxml2::XMLElement* node, std::string name);
|
||||
std::string queryStringParameter(tinyxml2::XMLElement* node, std::string name);
|
||||
bool queryBoolParameter(tinyxml2::XMLElement* node, std::string name);
|
||||
double queryDoubleParameter(tinyxml2::XMLElement* node, std::string name);
|
||||
void loadXML(std::string uri, tinyxml2::XMLDocument &doc);
|
||||
unsigned int queryUIntParameter(tinyxml2::XMLElement *node, std::string name);
|
||||
std::string queryStringParameter(tinyxml2::XMLElement *node, std::string name);
|
||||
bool queryBoolParameter(tinyxml2::XMLElement *node, std::string name);
|
||||
double queryDoubleParameter(tinyxml2::XMLElement *node, std::string name);
|
||||
|
||||
void setUpDummy(tlm::tlm_generic_payload& payload, Bank& bank);
|
||||
void setUpDummy(tlm::tlm_generic_payload &payload, Bank &bank);
|
||||
|
||||
#endif /* UTILS_COMMON_H_ */
|
||||
|
||||
|
||||
@@ -48,26 +48,32 @@ DramExtension::DramExtension() :
|
||||
{
|
||||
}
|
||||
|
||||
DramExtension::DramExtension(const Thread &thread, const Bank &bank, const BankGroup &bankgroup, const Row &row, const Column &column, unsigned int burstlength) :
|
||||
thread(thread), channel(0), bank(bank), bankgroup(bankgroup), row(row), column(column), burstlength(burstlength)
|
||||
DramExtension::DramExtension(const Thread &thread, const Bank &bank,
|
||||
const BankGroup &bankgroup, const Row &row, const Column &column,
|
||||
unsigned int burstlength) :
|
||||
thread(thread), channel(0), bank(bank), bankgroup(bankgroup), row(row),
|
||||
column(column), burstlength(burstlength)
|
||||
{
|
||||
}
|
||||
|
||||
DramExtension::DramExtension(const Thread &thread, const Channel &channel, const Bank &bank, const BankGroup &bankgroup, const Row &row, const Column &column, unsigned int burstlength) :
|
||||
thread(thread), channel(channel), bank(bank), bankgroup(bankgroup), row(row), column(column), burstlength(burstlength)
|
||||
DramExtension::DramExtension(const Thread &thread, const Channel &channel,
|
||||
const Bank &bank, const BankGroup &bankgroup, const Row &row,
|
||||
const Column &column, unsigned int burstlength) :
|
||||
thread(thread), channel(channel), bank(bank), bankgroup(bankgroup), row(row),
|
||||
column(column), burstlength(burstlength)
|
||||
{
|
||||
}
|
||||
|
||||
DramExtension& DramExtension::getExtension(const tlm_generic_payload *payload)
|
||||
DramExtension &DramExtension::getExtension(const tlm_generic_payload *payload)
|
||||
{
|
||||
DramExtension *result = NULL;
|
||||
payload->get_extension(result);
|
||||
sc_assert(result!=NULL);
|
||||
sc_assert(result != NULL);
|
||||
|
||||
return *result;
|
||||
}
|
||||
|
||||
DramExtension& DramExtension::getExtension(const tlm_generic_payload &payload)
|
||||
DramExtension &DramExtension::getExtension(const tlm_generic_payload &payload)
|
||||
{
|
||||
return DramExtension::getExtension(&payload);
|
||||
}
|
||||
@@ -113,14 +119,14 @@ Row DramExtension::getRow(const tlm_generic_payload &payload)
|
||||
}
|
||||
|
||||
|
||||
tlm_extension_base* DramExtension::clone() const
|
||||
tlm_extension_base *DramExtension::clone() const
|
||||
{
|
||||
return new DramExtension(thread, bank, bankgroup, row, column, burstlength);
|
||||
}
|
||||
|
||||
void DramExtension::copy_from(const tlm_extension_base& ext)
|
||||
void DramExtension::copy_from(const tlm_extension_base &ext)
|
||||
{
|
||||
const DramExtension& cpyFrom = static_cast<const DramExtension&>(ext);
|
||||
const DramExtension &cpyFrom = static_cast<const DramExtension &>(ext);
|
||||
thread = cpyFrom.thread;
|
||||
bank = cpyFrom.bank;
|
||||
bankgroup = cpyFrom.bankgroup;
|
||||
@@ -169,87 +175,91 @@ void DramExtension::incrementRow()
|
||||
++row;
|
||||
}
|
||||
|
||||
tlm_extension_base* GenerationExtension::clone() const
|
||||
tlm_extension_base *GenerationExtension::clone() const
|
||||
{
|
||||
return new GenerationExtension(timeOfGeneration);
|
||||
}
|
||||
|
||||
void GenerationExtension::copy_from(const tlm_extension_base& ext)
|
||||
void GenerationExtension::copy_from(const tlm_extension_base &ext)
|
||||
{
|
||||
const GenerationExtension& cpyFrom = static_cast<const GenerationExtension&>(ext);
|
||||
const GenerationExtension &cpyFrom = static_cast<const GenerationExtension &>
|
||||
(ext);
|
||||
timeOfGeneration = cpyFrom.timeOfGeneration;
|
||||
|
||||
}
|
||||
|
||||
GenerationExtension& GenerationExtension::getExtension(const tlm::tlm_generic_payload* payload)
|
||||
GenerationExtension &GenerationExtension::getExtension(const
|
||||
tlm::tlm_generic_payload *payload)
|
||||
{
|
||||
GenerationExtension *result = NULL;
|
||||
payload->get_extension(result);
|
||||
sc_assert(result!=NULL);
|
||||
sc_assert(result != NULL);
|
||||
return *result;
|
||||
}
|
||||
|
||||
sc_time GenerationExtension::getTimeOfGeneration(const tlm::tlm_generic_payload *payload)
|
||||
sc_time GenerationExtension::getTimeOfGeneration(const tlm::tlm_generic_payload
|
||||
*payload)
|
||||
{
|
||||
return GenerationExtension::getExtension(payload).TimeOfGeneration();
|
||||
}
|
||||
|
||||
sc_time GenerationExtension::getTimeOfGeneration(const tlm::tlm_generic_payload &payload)
|
||||
sc_time GenerationExtension::getTimeOfGeneration(const tlm::tlm_generic_payload
|
||||
&payload)
|
||||
{
|
||||
return GenerationExtension::getTimeOfGeneration(&payload);
|
||||
}
|
||||
|
||||
//THREAD
|
||||
bool operator ==(const Thread& lhs, const Thread& rhs)
|
||||
bool operator ==(const Thread &lhs, const Thread &rhs)
|
||||
{
|
||||
return lhs.ID() == rhs.ID();
|
||||
}
|
||||
|
||||
bool operator !=(const Thread& lhs, const Thread& rhs)
|
||||
bool operator !=(const Thread &lhs, const Thread &rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
bool operator <(const Thread& lhs, const Thread& rhs)
|
||||
bool operator <(const Thread &lhs, const Thread &rhs)
|
||||
{
|
||||
return lhs.ID() < rhs.ID();
|
||||
}
|
||||
|
||||
//CHANNEL
|
||||
bool operator ==(const Channel& lhs, const Channel& rhs)
|
||||
bool operator ==(const Channel &lhs, const Channel &rhs)
|
||||
{
|
||||
return lhs.ID() == rhs.ID();
|
||||
}
|
||||
|
||||
bool operator !=(const Channel& lhs, const Channel& rhs)
|
||||
bool operator !=(const Channel &lhs, const Channel &rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
|
||||
//BANKGROUP
|
||||
bool operator ==(const BankGroup& lhs, const BankGroup& rhs)
|
||||
bool operator ==(const BankGroup &lhs, const BankGroup &rhs)
|
||||
{
|
||||
return lhs.ID() == rhs.ID();
|
||||
}
|
||||
|
||||
bool operator !=(const BankGroup& lhs, const BankGroup& rhs)
|
||||
bool operator !=(const BankGroup &lhs, const BankGroup &rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
//BANK
|
||||
bool operator ==(const Bank& lhs, const Bank& rhs)
|
||||
bool operator ==(const Bank &lhs, const Bank &rhs)
|
||||
{
|
||||
return lhs.ID() == rhs.ID();
|
||||
}
|
||||
|
||||
bool operator !=(const Bank& lhs, const Bank& rhs)
|
||||
bool operator !=(const Bank &lhs, const Bank &rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
bool operator <(const Bank& lhs, const Bank& rhs)
|
||||
bool operator <(const Bank &lhs, const Bank &rhs)
|
||||
{
|
||||
return lhs.ID() < rhs.ID();
|
||||
}
|
||||
@@ -257,14 +267,14 @@ bool operator <(const Bank& lhs, const Bank& rhs)
|
||||
//ROW
|
||||
const Row Row::NO_ROW;
|
||||
|
||||
bool operator ==(const Row& lhs, const Row& rhs)
|
||||
bool operator ==(const Row &lhs, const Row &rhs)
|
||||
{
|
||||
if (lhs.isNoRow != rhs.isNoRow)
|
||||
return false;
|
||||
return lhs.ID() == rhs.ID();
|
||||
}
|
||||
|
||||
bool operator !=(const Row& lhs, const Row& rhs)
|
||||
bool operator !=(const Row &lhs, const Row &rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
@@ -277,12 +287,12 @@ const Row Row::operator ++()
|
||||
|
||||
|
||||
//COLUMN
|
||||
bool operator ==(const Column& lhs, const Column& rhs)
|
||||
bool operator ==(const Column &lhs, const Column &rhs)
|
||||
{
|
||||
return lhs.ID() == rhs.ID();
|
||||
}
|
||||
|
||||
bool operator !=(const Column& lhs, const Column& rhs)
|
||||
bool operator !=(const Column &lhs, const Column &rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ class Thread
|
||||
{
|
||||
public:
|
||||
explicit Thread(unsigned int id) :
|
||||
id(id)
|
||||
id(id)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ class Channel
|
||||
{
|
||||
public:
|
||||
explicit Channel(unsigned int id) :
|
||||
id(id)
|
||||
id(id)
|
||||
{
|
||||
}
|
||||
unsigned int ID() const
|
||||
@@ -77,7 +77,7 @@ class BankGroup
|
||||
{
|
||||
public:
|
||||
explicit BankGroup(unsigned int id) :
|
||||
id(id)
|
||||
id(id)
|
||||
{
|
||||
}
|
||||
unsigned int ID() const
|
||||
@@ -92,7 +92,7 @@ class Bank
|
||||
{
|
||||
public:
|
||||
Bank(unsigned int id) :
|
||||
id(id)
|
||||
id(id)
|
||||
{
|
||||
}
|
||||
unsigned int ID() const
|
||||
@@ -121,11 +121,11 @@ public:
|
||||
static const Row NO_ROW;
|
||||
|
||||
Row() :
|
||||
id(0), isNoRow(true)
|
||||
id(0), isNoRow(true)
|
||||
{
|
||||
}
|
||||
explicit Row(unsigned int id) :
|
||||
id(id), isNoRow(false)
|
||||
id(id), isNoRow(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ class Column
|
||||
{
|
||||
public:
|
||||
explicit Column(unsigned int id) :
|
||||
id(id)
|
||||
id(id)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -163,16 +163,18 @@ class DramExtension: public tlm::tlm_extension<DramExtension>
|
||||
{
|
||||
public:
|
||||
DramExtension();
|
||||
DramExtension(const Thread& thread, const Bank& bank, const BankGroup& bankgroup, const Row& row, const Column& column,
|
||||
unsigned int burstlength = 0);
|
||||
DramExtension(const Thread& thread, const Channel& channel, const Bank& bank, const BankGroup& bankgroup, const Row& row,
|
||||
const Column& column, unsigned int burstlength = 0);
|
||||
DramExtension(const Thread &thread, const Bank &bank,
|
||||
const BankGroup &bankgroup, const Row &row, const Column &column,
|
||||
unsigned int burstlength = 0);
|
||||
DramExtension(const Thread &thread, const Channel &channel, const Bank &bank,
|
||||
const BankGroup &bankgroup, const Row &row,
|
||||
const Column &column, unsigned int burstlength = 0);
|
||||
|
||||
virtual tlm_extension_base* clone() const;
|
||||
virtual void copy_from(const tlm_extension_base& ext);
|
||||
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);
|
||||
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);
|
||||
@@ -211,11 +213,16 @@ private:
|
||||
class GenerationExtension : public tlm::tlm_extension<GenerationExtension>
|
||||
{
|
||||
public:
|
||||
GenerationExtension(sc_time timeOfGeneration) : timeOfGeneration(timeOfGeneration) {}
|
||||
virtual tlm_extension_base* clone() const;
|
||||
virtual void copy_from(const tlm_extension_base& ext);
|
||||
static GenerationExtension& getExtension(const tlm::tlm_generic_payload *payload);
|
||||
sc_time TimeOfGeneration() const {return timeOfGeneration;}
|
||||
GenerationExtension(sc_time timeOfGeneration) : timeOfGeneration(
|
||||
timeOfGeneration) {}
|
||||
virtual tlm_extension_base *clone() const;
|
||||
virtual void copy_from(const tlm_extension_base &ext);
|
||||
static GenerationExtension &getExtension(const tlm::tlm_generic_payload
|
||||
*payload);
|
||||
sc_time TimeOfGeneration() const
|
||||
{
|
||||
return timeOfGeneration;
|
||||
}
|
||||
static sc_time getTimeOfGeneration(const tlm::tlm_generic_payload *payload);
|
||||
static sc_time getTimeOfGeneration(const tlm::tlm_generic_payload &payload);
|
||||
|
||||
|
||||
272
DRAMSys/library/src/common/jsonAddressDecoder.cpp
Normal file
272
DRAMSys/library/src/common/jsonAddressDecoder.cpp
Normal file
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* Copyright (c) 2018, University of Kaiserslautern
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Authors:
|
||||
* Johannes Feldmann
|
||||
*/
|
||||
|
||||
#include "jsonAddressDecoder.h"
|
||||
#include "Utils.h"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
using std::ifstream;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
#if 0 // Problems with gcc version on KOA for more details refer to pull-request #190 and issue #198
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
#endif
|
||||
|
||||
#include <set>
|
||||
|
||||
using std::set;
|
||||
|
||||
JSONAddressDecoder::JSONAddressDecoder()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void JSONAddressDecoder::setConfiguration(std::string url)
|
||||
{
|
||||
ifstream file;
|
||||
|
||||
file.open(url);
|
||||
|
||||
if (!file.is_open()) {
|
||||
cout << "Unable to open file " << url << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0 //XXX: Problems with gcc version on KOA for more details refer to pull-request #190 and issue #198
|
||||
// parse json file
|
||||
json data;
|
||||
file >> data;
|
||||
|
||||
file.close();
|
||||
|
||||
// extract data
|
||||
// For simplicity take the first solution of one or more available ones.
|
||||
auto sol = data["Solutions"].begin();
|
||||
assert(sol != data["Solutions"].end());
|
||||
|
||||
// Set for connected bits. Used to find the remaining bits, which are not part of the json file = column bits.
|
||||
set<unsigned> sUsed;
|
||||
|
||||
// get XOR connections
|
||||
// An XOR connection needs two parameters: A bank bit and a Row bit.
|
||||
// These parameters are all stored in one array with the following pattern: bank0, bank1, ..., row0, row1, ...
|
||||
unsigned num = (*sol)["XOR"].size() >> 1;
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
m_vXor.push_back(pair<unsigned, unsigned> ((*sol)["XOR"].at(i),
|
||||
(*sol)["XOR"].at(i + num)));
|
||||
}
|
||||
|
||||
// get all bank bits
|
||||
// Each bank bit of the address will be stored with a counter value which assigns the bit position DecodedAddress struct.
|
||||
unsigned counter = 0;
|
||||
for (auto it = (*sol)["Banks Rows"][0]["bank_bits"].begin();
|
||||
it != (*sol)["Banks Rows"][0]["bank_bits"].end(); it++) {
|
||||
m_vBankBits.push_back(pair<unsigned, unsigned>(counter++, (*it)));
|
||||
sUsed.insert((unsigned)(*it));
|
||||
}
|
||||
|
||||
// get all row bits bits
|
||||
// Each Row bit of the address will be stored with a counter value which assigns the bit position DecodedAddress struct.
|
||||
counter = 0;
|
||||
for (auto it = (*sol)["Banks Rows"][0]["rows"]["row_bits"].begin();
|
||||
it != (*sol)["Banks Rows"][0]["rows"]["row_bits"].end(); it++) {
|
||||
m_vRowBits.push_back(pair<unsigned, unsigned>(counter++, (*it)));
|
||||
sUsed.insert((unsigned)(*it));
|
||||
}
|
||||
|
||||
// Add byte bits (fixed)
|
||||
sUsed.insert(0);
|
||||
sUsed.insert(1);
|
||||
sUsed.insert(2);
|
||||
|
||||
// Theset bits are ignored
|
||||
sUsed.insert(30);
|
||||
sUsed.insert(31);
|
||||
|
||||
// Create Column mapping
|
||||
// These bits are not stored in the JSON file, but can be generated. All bits, which are until now not used for any other purpose are column bits.
|
||||
// Each column bit of the address will be stored with a counter value which assigns the bit position DecodedAddress struct.
|
||||
counter = 0;
|
||||
for (unsigned i = 0; i < 32; i++) {
|
||||
if (sUsed.find(i) != sUsed.end())
|
||||
continue; // Already mapped
|
||||
|
||||
m_vColumnBits.push_back(pair<unsigned, unsigned>(counter++, i));
|
||||
}
|
||||
|
||||
// Fill the amount map. This is copied from xmlAddressDecoder without further investigation
|
||||
amount["channel"] = 1;
|
||||
amount["bank"] = pow(2.0, m_vBankBits.size());
|
||||
amount["row"] = pow(2.0, m_vRowBits.size());
|
||||
amount["column"] = pow(2.0, m_vColumnBits.size());
|
||||
amount["bytes"] = pow(2.0, 3);
|
||||
#endif
|
||||
}
|
||||
|
||||
DecodedAddress JSONAddressDecoder::decodeAddress(sc_dt::uint64 addr)
|
||||
{
|
||||
DecodedAddress result;
|
||||
|
||||
// Apply XOR
|
||||
// For each used xor:
|
||||
// Get the bank bit and row bit. Apply a bitwise xor operator and save it back to the bank bit.
|
||||
for (auto it = m_vXor.begin(); it != m_vXor.end(); it++) {
|
||||
unsigned new_bank_bit;
|
||||
// Bank Row
|
||||
new_bank_bit = (((addr >> it->first) & 1) ^ ((addr >> it->second) & 1));
|
||||
addr &= ~(1 << it->first);
|
||||
addr |= new_bank_bit << it->first;
|
||||
}
|
||||
|
||||
// Unsed
|
||||
result.bankgroup = 0;
|
||||
result.channel = 0;
|
||||
result.rank = 0;
|
||||
|
||||
// Pass through of the three byte bits
|
||||
result.bytes = addr & 0x7;
|
||||
|
||||
// Bank
|
||||
// it->second: position of the target bit in the address
|
||||
// it->first: target position of the bit in the variable
|
||||
// For each bank bit:
|
||||
// shift address bit to position 0. Clear all other bits. shift it the right bank bit. Add it to the set of bank bits.
|
||||
result.bank = 0;
|
||||
for (auto it = m_vBankBits.begin(); it != m_vBankBits.end(); it++) {
|
||||
result.bank |= ((addr >> it->second) & 1) << it->first;
|
||||
}
|
||||
|
||||
// Row
|
||||
// it->second: position of the target bit in the address
|
||||
// it->first: target position of the bit in the variable
|
||||
// For each row bit:
|
||||
// shift address bit to position 0. Clear all other bits. shift it the right row bit. Add it to the set of row bits.
|
||||
result.row = 0;
|
||||
for (auto it = m_vRowBits.begin(); it != m_vRowBits.end(); it++) {
|
||||
result.row |= ((addr >> it->second) & 1) << it->first;
|
||||
}
|
||||
|
||||
// Column
|
||||
// it->second: position of the target bit in the address
|
||||
// it->first: target position of the bit in the variable
|
||||
// For each column bit:
|
||||
// shift address bit to position 0. Clear all other bits. shift it the right column bit. Add it to the set of column bits.
|
||||
result.column = 0;
|
||||
for (auto it = m_vColumnBits.begin(); it != m_vColumnBits.end(); it++) {
|
||||
result.column |= ((addr >> it->second) & 1) << it->first;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
sc_dt::uint64 JSONAddressDecoder::encodeAddress(DecodedAddress n)
|
||||
{
|
||||
sc_dt::uint64 address = 0;
|
||||
|
||||
// Bank
|
||||
// it->first: position of the target bit in the DecodedAddress struct field
|
||||
// it->second: target position of the bit in the address
|
||||
// For each bank bit:
|
||||
// shift bank bit to position 0. Clear all other bits. shift it the right address bit. Add it to the set of address bits.
|
||||
for (auto it = m_vBankBits.begin(); it != m_vBankBits.end(); it++) {
|
||||
address |= ((n.bank >> it->first) & 1) << it->second;
|
||||
}
|
||||
// Row
|
||||
// it->first: position of the target bit in the DecodedAddress struct field
|
||||
// it->second: target position of the bit in the address
|
||||
// For each row bit:
|
||||
// shift row bit to position 0. Clear all other bits. shift it the right address bit. Add it to the set of address bits.
|
||||
for (auto it = m_vRowBits.begin(); it != m_vRowBits.end(); it++) {
|
||||
address |= ((n.row >> it->first) & 1) << it->second;
|
||||
}
|
||||
// Column
|
||||
// it->first: position of the target bit in the DecodedAddress struct field
|
||||
// it->second: target position of the bit in the address
|
||||
// For each column bit:
|
||||
// shift column bit to position 0. Clear all other bits. shift it the right address bit. Add it to the set of address bits.
|
||||
for (auto it = m_vColumnBits.begin(); it != m_vColumnBits.end(); it++) {
|
||||
address |= ((n.column >> it->first) & 1) << it->second;
|
||||
}
|
||||
|
||||
// Add the unchanged byte bits
|
||||
address |= n.bytes;
|
||||
|
||||
// Apply XOR
|
||||
// For each used xor:
|
||||
// Get the bank bit and row bit. Apply a bitwise xor operator and save it back to the bank bit.
|
||||
for (auto it = m_vXor.begin(); it != m_vXor.end(); it++) {
|
||||
unsigned new_bank_bit;
|
||||
new_bank_bit = (((address >> it->first) & 1) ^ ((address >> it->second) & 1));
|
||||
address &= ~(1 << it->first);
|
||||
address |= new_bank_bit << it->first;
|
||||
}
|
||||
|
||||
return address;
|
||||
}
|
||||
|
||||
void JSONAddressDecoder::print()
|
||||
{
|
||||
map<unsigned, pair<unsigned, char>> output;
|
||||
|
||||
for (auto it = m_vBankBits.begin(); it != m_vBankBits.end(); it++) {
|
||||
output[it->second] = pair<unsigned, char>(it->first , 'B');
|
||||
}
|
||||
for (auto it = m_vRowBits.begin(); it != m_vRowBits.end(); it++) {
|
||||
output[it->second] = pair<unsigned, char>(it->first , 'R');
|
||||
}
|
||||
for (auto it = m_vColumnBits.begin(); it != m_vColumnBits.end(); it++) {
|
||||
output[it->second] = pair<unsigned, char>(it->first , 'C');
|
||||
}
|
||||
|
||||
// add byte bits
|
||||
output[0] = pair<unsigned, char>(0 , 'b');
|
||||
output[1] = pair<unsigned, char>(1 , 'b');
|
||||
output[2] = pair<unsigned, char>(2 , 'b');
|
||||
|
||||
cout << "Used addressmapping:" << endl;
|
||||
cout << headline << endl;
|
||||
for (unsigned i = 0; i < 32; i++) {
|
||||
cout << " " << i << " ";
|
||||
}
|
||||
cout << endl;
|
||||
for (unsigned i = 0; i < 32; i++) {
|
||||
cout << " " << output[i].second << "(" << output[i].first << ") ";
|
||||
}
|
||||
cout << endl;
|
||||
}
|
||||
77
DRAMSys/library/src/common/jsonAddressDecoder.h
Normal file
77
DRAMSys/library/src/common/jsonAddressDecoder.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2018, University of Kaiserslautern
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Authors:
|
||||
* Johannes Feldmann
|
||||
*/
|
||||
|
||||
#ifndef JSONADDRESSDECODER_H
|
||||
#define JSONADDRESSDECODER_H
|
||||
|
||||
#include "AddressDecoder.h"
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
using std::vector;
|
||||
using std::pair;
|
||||
using std::map;
|
||||
|
||||
class JSONAddressDecoder
|
||||
: public AddressDecoder
|
||||
{
|
||||
// Friendship needed so that the AddressDecoder can access the
|
||||
// constructor of this class to create the object in CreateInstance.
|
||||
friend class AddressDecoder;
|
||||
|
||||
private:
|
||||
JSONAddressDecoder();
|
||||
|
||||
vector<pair<unsigned, unsigned>>
|
||||
m_vXor; // This container stores for each used xor gate a pair which consists of "First/Number of an address bit which corresponds to a bank"
|
||||
// and "Second/Number of an address bit which corresponds to a row"
|
||||
vector<pair<unsigned, unsigned>>
|
||||
m_vBankBits; // This container stores for each bank bit a pair which consists of "First/Number of the bank bit" and "Second/Number of the address bit"
|
||||
vector<pair<unsigned, unsigned>>
|
||||
m_vRowBits; // This container stores for each row bit a pair which consists of "First/Number of the row bit" and "Second/Number of the address bit"
|
||||
vector<pair<unsigned, unsigned>>
|
||||
m_vColumnBits; // This container stores for each column bit a pair which consists of "First/Number of the column bit" and "Second/Number of the address bit"
|
||||
|
||||
public:
|
||||
virtual void setConfiguration(std::string url);
|
||||
|
||||
virtual DecodedAddress decodeAddress(sc_dt::uint64 addr);
|
||||
virtual sc_dt::uint64 encodeAddress(DecodedAddress n);
|
||||
|
||||
virtual void print();
|
||||
};
|
||||
|
||||
#endif // JSONADDRESSDECODER_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -49,37 +49,20 @@ xmlAddressDecoder::xmlAddressDecoder()
|
||||
addressmapping = NULL;
|
||||
}
|
||||
|
||||
xmlAddressDecoder::xmlAddressDecoder(string addressConfigURI)
|
||||
{
|
||||
setConfiguration(addressConfigURI);
|
||||
}
|
||||
|
||||
xmlAddressDecoder::xmlAddressDecoder(XMLElement* addressmap)
|
||||
{
|
||||
setConfiguration(addressmap);
|
||||
}
|
||||
|
||||
void xmlAddressDecoder::setConfiguration(std::string addressConfigURI)
|
||||
{
|
||||
tinyxml2::XMLDocument doc;
|
||||
loadXML(addressConfigURI, doc);
|
||||
setConfiguration(doc.RootElement());
|
||||
}
|
||||
|
||||
void xmlAddressDecoder::setConfiguration(tinyxml2::XMLElement* addressMap)
|
||||
{
|
||||
tinyxml2::XMLDocument doc;
|
||||
tinyxml2::XMLElement *addressMap = doc.RootElement();
|
||||
string xmlNodeName(addressMap->Name());
|
||||
|
||||
if( xmlNodeName != "addressmapping")
|
||||
{
|
||||
if ( xmlNodeName != "addressmapping") {
|
||||
reportFatal("AddressDecorder", "addressmap node expected");
|
||||
}
|
||||
|
||||
for(XMLElement* child = addressMap->FirstChildElement();
|
||||
child != NULL;
|
||||
child = child->NextSiblingElement())
|
||||
{
|
||||
for (XMLElement *child = addressMap->FirstChildElement();
|
||||
child != NULL;
|
||||
child = child->NextSiblingElement()) {
|
||||
int from;
|
||||
int to;
|
||||
|
||||
@@ -100,7 +83,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 % Configuration::getInstance().memSpec.NumberOfBankGroups;
|
||||
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"];
|
||||
@@ -111,21 +95,20 @@ DecodedAddress xmlAddressDecoder::decodeAddress(sc_dt::uint64 addr)
|
||||
sc_dt::uint64 xmlAddressDecoder::encodeAddress(DecodedAddress n)
|
||||
{
|
||||
return n.channel << shifts["channel"] |
|
||||
n.rank << shifts["rank"] |
|
||||
n.bankgroup << shifts["bankgroup"] |
|
||||
n.row << shifts["row"] |
|
||||
n.bank << shifts["bank"] |
|
||||
n.column << shifts["column"] |
|
||||
n.bytes << shifts["bytes"];
|
||||
n.rank << shifts["rank"] |
|
||||
n.bankgroup << shifts["bankgroup"] |
|
||||
n.row << shifts["row"] |
|
||||
n.bank << shifts["bank"] |
|
||||
n.column << shifts["column"] |
|
||||
n.bytes << shifts["bytes"];
|
||||
}
|
||||
|
||||
void xmlAddressDecoder::print()
|
||||
{
|
||||
cout << "Used addressmapping:" << endl;
|
||||
cout << headline << endl;
|
||||
for(auto& pair : masks)
|
||||
{
|
||||
cout<<pair.first<<"\t:\t" << bitset<32>(pair.second)<<endl;
|
||||
for (auto &pair : masks) {
|
||||
cout << pair.first << "\t:\t" << bitset<32>(pair.second) << endl;
|
||||
}
|
||||
cout<<"\n"<<endl;
|
||||
cout << "\n" << endl;
|
||||
}
|
||||
|
||||
@@ -38,62 +38,35 @@
|
||||
#ifndef _XMLADDRESSDECODER_H
|
||||
#define _XMLADDRESSDECODER_H
|
||||
|
||||
#include <tlm.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <math.h>
|
||||
#include <map>
|
||||
|
||||
#include "Utils.h"
|
||||
#include "third_party/tinyxml2/tinyxml2.h"
|
||||
|
||||
struct DecodedAddress
|
||||
{
|
||||
DecodedAddress() : channel(0),
|
||||
rank(0),
|
||||
bankgroup(0),
|
||||
row(0),
|
||||
bank(0),
|
||||
column(0),
|
||||
bytes(0)
|
||||
{
|
||||
}
|
||||
|
||||
unsigned int channel;
|
||||
unsigned int rank;
|
||||
unsigned int bankgroup;
|
||||
unsigned int row;
|
||||
unsigned int bank;
|
||||
unsigned int column;
|
||||
unsigned int bytes;
|
||||
};
|
||||
#include "AddressDecoder.h"
|
||||
|
||||
class xmlAddressDecoder
|
||||
: public AddressDecoder
|
||||
{
|
||||
// Friendship needed so that the AddressDecoder can access the
|
||||
// constructor of this class to create the object in CreateInstance.
|
||||
friend class AddressDecoder;
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
xmlAddressDecoder();
|
||||
xmlAddressDecoder(std::string URI);
|
||||
xmlAddressDecoder(tinyxml2::XMLElement* addressMap);
|
||||
|
||||
std::map<std::string, sc_dt::uint64> masks;
|
||||
std::map<std::string, unsigned int> shifts;
|
||||
|
||||
tinyxml2::XMLElement* addressmapping;
|
||||
tinyxml2::XMLElement *addressmapping;
|
||||
|
||||
public:
|
||||
DEF_SINGLETON(xmlAddressDecoder);
|
||||
|
||||
DecodedAddress decodeAddress(sc_dt::uint64 addr);
|
||||
sc_dt::uint64 encodeAddress(DecodedAddress n);
|
||||
public:
|
||||
virtual DecodedAddress decodeAddress(sc_dt::uint64 addr);
|
||||
virtual sc_dt::uint64 encodeAddress(DecodedAddress n);
|
||||
|
||||
void setConfiguration(std::string url);
|
||||
void setConfiguration(tinyxml2::XMLElement* addressMap);
|
||||
void print();
|
||||
|
||||
std::map<std::string, unsigned int> amount;
|
||||
public:
|
||||
virtual void print();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -41,8 +41,7 @@
|
||||
|
||||
std::string commandToString(Command command)
|
||||
{
|
||||
switch (command)
|
||||
{
|
||||
switch (command) {
|
||||
case Command::Read:
|
||||
return "RD";
|
||||
break;
|
||||
@@ -99,19 +98,19 @@ std::string commandToString(Command command)
|
||||
return "";
|
||||
}
|
||||
|
||||
const std::vector<Command>& getAllCommands()
|
||||
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 });
|
||||
Command::SREF, Command::SREFX
|
||||
});
|
||||
return allCommands;
|
||||
}
|
||||
|
||||
bool commandIsIn(Command command, std::vector<Command> commands)
|
||||
{
|
||||
for (Command c : commands)
|
||||
{
|
||||
for (Command c : commands) {
|
||||
if (c == command)
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
|
||||
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();
|
||||
const std::vector<Command> &getAllCommands();
|
||||
bool commandIsIn(Command command, std::vector<Command> commands);
|
||||
|
||||
#endif /* COMMAND_H_ */
|
||||
|
||||
@@ -43,29 +43,19 @@ void Controller::buildScheduler()
|
||||
string selectedScheduler = Configuration::getInstance().Scheduler;
|
||||
std::cout << "Selected Scheduler: " << selectedScheduler << std::endl;
|
||||
|
||||
if (selectedScheduler == "FIFO")
|
||||
{
|
||||
if (selectedScheduler == "FIFO") {
|
||||
scheduler = new Fifo(*controllerCore);
|
||||
}
|
||||
else if (selectedScheduler == "FIFO_STRICT")
|
||||
{
|
||||
} else if (selectedScheduler == "FIFO_STRICT") {
|
||||
scheduler = new FifoStrict(*this, *controllerCore);
|
||||
}
|
||||
else if (selectedScheduler == "FR_FCFS")
|
||||
{
|
||||
} else if (selectedScheduler == "FR_FCFS") {
|
||||
scheduler = new FR_FCFS(*controllerCore);
|
||||
}
|
||||
else if (selectedScheduler == "FR_FCFS_RP")
|
||||
{
|
||||
} else if (selectedScheduler == "FR_FCFS_RP") {
|
||||
scheduler = new FR_FCFS_RP(*controllerCore);
|
||||
}
|
||||
else if (selectedScheduler == "FR_FCFS_GRP")
|
||||
{
|
||||
scheduler = new FR_FCFS_GRP(*controllerCore,this);
|
||||
}
|
||||
else if (selectedScheduler == "SMS")
|
||||
{
|
||||
scheduler = new SMS("SMS", *controllerCore, Configuration::getInstance().SJFProbability);
|
||||
} else if (selectedScheduler == "FR_FCFS_GRP") {
|
||||
scheduler = new FR_FCFS_GRP(*controllerCore, this);
|
||||
} else if (selectedScheduler == "SMS") {
|
||||
scheduler = new SMS("SMS", *controllerCore,
|
||||
Configuration::getInstance().SJFProbability);
|
||||
}
|
||||
//else if (selectedScheduler == "PAR_BS")
|
||||
//{
|
||||
@@ -81,98 +71,105 @@ void Controller::buildScheduler()
|
||||
}
|
||||
|
||||
//Send the next scheduled command to the DRAM
|
||||
void Controller::send(const ScheduledCommand &command, tlm_generic_payload &payload)
|
||||
void Controller::send(const ScheduledCommand &command,
|
||||
tlm_generic_payload &payload)
|
||||
{
|
||||
sc_assert(command.getStart() >= sc_time_stamp());
|
||||
TimeInterval dataStrobe;
|
||||
|
||||
switch (command.getCommand())
|
||||
{
|
||||
switch (command.getCommand()) {
|
||||
//TODO: refactor tlm recorder
|
||||
case Command::Read:
|
||||
dataStrobe = command.getIntervalOnDataStrobe();
|
||||
tlmRecorder->updateDataStrobe(dataStrobe.start, dataStrobe.end, payload);
|
||||
controllerCorePEQ.notify(payload, BEGIN_RD, command.getStart() - sc_time_stamp());
|
||||
controllerCorePEQ.notify(payload, BEGIN_RD,
|
||||
command.getStart() - sc_time_stamp());
|
||||
break;
|
||||
case Command::ReadA:
|
||||
dataStrobe = command.getIntervalOnDataStrobe();
|
||||
tlmRecorder->updateDataStrobe(dataStrobe.start, dataStrobe.end, payload);
|
||||
controllerCorePEQ.notify(payload, BEGIN_RDA, command.getStart() - sc_time_stamp());
|
||||
controllerCorePEQ.notify(payload, BEGIN_RDA,
|
||||
command.getStart() - sc_time_stamp());
|
||||
break;
|
||||
case Command::Write:
|
||||
dataStrobe = command.getIntervalOnDataStrobe();
|
||||
tlmRecorder->updateDataStrobe(dataStrobe.start, dataStrobe.end, payload);
|
||||
controllerCorePEQ.notify(payload, BEGIN_WR, command.getStart() - sc_time_stamp());
|
||||
controllerCorePEQ.notify(payload, BEGIN_WR,
|
||||
command.getStart() - sc_time_stamp());
|
||||
break;
|
||||
case Command::WriteA:
|
||||
dataStrobe = command.getIntervalOnDataStrobe();
|
||||
tlmRecorder->updateDataStrobe(dataStrobe.start, dataStrobe.end, payload);
|
||||
controllerCorePEQ.notify(payload, BEGIN_WRA, command.getStart() - sc_time_stamp());
|
||||
controllerCorePEQ.notify(payload, BEGIN_WRA,
|
||||
command.getStart() - sc_time_stamp());
|
||||
break;
|
||||
case Command::AutoRefresh:
|
||||
if(!Configuration::getInstance().BankwiseLogic)
|
||||
{
|
||||
controllerCorePEQ.notify(payload, BEGIN_REFA, command.getStart() - sc_time_stamp());
|
||||
}
|
||||
else
|
||||
controllerCorePEQ.notify(payload, BEGIN_REFB, command.getStart() - sc_time_stamp());
|
||||
if (!Configuration::getInstance().BankwiseLogic) {
|
||||
controllerCorePEQ.notify(payload, BEGIN_REFA,
|
||||
command.getStart() - sc_time_stamp());
|
||||
} else
|
||||
controllerCorePEQ.notify(payload, BEGIN_REFB,
|
||||
command.getStart() - sc_time_stamp());
|
||||
break;
|
||||
case Command::Activate:
|
||||
controllerCorePEQ.notify(payload, BEGIN_ACT, command.getStart() - sc_time_stamp());
|
||||
controllerCorePEQ.notify(payload, BEGIN_ACT,
|
||||
command.getStart() - sc_time_stamp());
|
||||
break;
|
||||
case Command::Precharge:
|
||||
controllerCorePEQ.notify(payload, BEGIN_PRE, command.getStart() - sc_time_stamp());
|
||||
controllerCorePEQ.notify(payload, BEGIN_PRE,
|
||||
command.getStart() - sc_time_stamp());
|
||||
break;
|
||||
case Command::PrechargeAll:
|
||||
controllerCorePEQ.notify(payload, BEGIN_PRE_ALL, command.getStart() - sc_time_stamp());
|
||||
controllerCorePEQ.notify(payload, BEGIN_PRE_ALL,
|
||||
command.getStart() - sc_time_stamp());
|
||||
break;
|
||||
case Command::PDNA:
|
||||
if(!Configuration::getInstance().BankwiseLogic)
|
||||
{
|
||||
controllerCorePEQ.notify(payload, BEGIN_PDNA, command.getStart() - sc_time_stamp());
|
||||
}
|
||||
else
|
||||
controllerCorePEQ.notify(payload, BEGIN_PDNAB, command.getStart() - sc_time_stamp());
|
||||
if (!Configuration::getInstance().BankwiseLogic) {
|
||||
controllerCorePEQ.notify(payload, BEGIN_PDNA,
|
||||
command.getStart() - sc_time_stamp());
|
||||
} else
|
||||
controllerCorePEQ.notify(payload, BEGIN_PDNAB,
|
||||
command.getStart() - sc_time_stamp());
|
||||
break;
|
||||
case Command::PDNAX:
|
||||
if(!Configuration::getInstance().BankwiseLogic)
|
||||
{
|
||||
controllerCorePEQ.notify(payload, END_PDNA, command.getStart() - sc_time_stamp());
|
||||
}
|
||||
else
|
||||
controllerCorePEQ.notify(payload, END_PDNAB, command.getStart() - sc_time_stamp());
|
||||
if (!Configuration::getInstance().BankwiseLogic) {
|
||||
controllerCorePEQ.notify(payload, END_PDNA,
|
||||
command.getStart() - sc_time_stamp());
|
||||
} else
|
||||
controllerCorePEQ.notify(payload, END_PDNAB,
|
||||
command.getStart() - sc_time_stamp());
|
||||
break;
|
||||
case Command::PDNP:
|
||||
if(!Configuration::getInstance().BankwiseLogic)
|
||||
{
|
||||
controllerCorePEQ.notify(payload, BEGIN_PDNP, command.getStart() - sc_time_stamp());
|
||||
}
|
||||
else
|
||||
controllerCorePEQ.notify(payload, BEGIN_PDNPB, command.getStart() - sc_time_stamp());
|
||||
if (!Configuration::getInstance().BankwiseLogic) {
|
||||
controllerCorePEQ.notify(payload, BEGIN_PDNP,
|
||||
command.getStart() - sc_time_stamp());
|
||||
} else
|
||||
controllerCorePEQ.notify(payload, BEGIN_PDNPB,
|
||||
command.getStart() - sc_time_stamp());
|
||||
break;
|
||||
case Command::PDNPX:
|
||||
if(!Configuration::getInstance().BankwiseLogic)
|
||||
{
|
||||
controllerCorePEQ.notify(payload, END_PDNP, command.getStart() - sc_time_stamp());
|
||||
}
|
||||
else
|
||||
controllerCorePEQ.notify(payload, END_PDNPB, command.getStart() - sc_time_stamp());
|
||||
if (!Configuration::getInstance().BankwiseLogic) {
|
||||
controllerCorePEQ.notify(payload, END_PDNP,
|
||||
command.getStart() - sc_time_stamp());
|
||||
} else
|
||||
controllerCorePEQ.notify(payload, END_PDNPB,
|
||||
command.getStart() - sc_time_stamp());
|
||||
break;
|
||||
case Command::SREF:
|
||||
if(!Configuration::getInstance().BankwiseLogic)
|
||||
{
|
||||
controllerCorePEQ.notify(payload, BEGIN_SREF, command.getStart() - sc_time_stamp());
|
||||
}
|
||||
else
|
||||
controllerCorePEQ.notify(payload, BEGIN_SREFB, command.getStart() - sc_time_stamp());
|
||||
if (!Configuration::getInstance().BankwiseLogic) {
|
||||
controllerCorePEQ.notify(payload, BEGIN_SREF,
|
||||
command.getStart() - sc_time_stamp());
|
||||
} else
|
||||
controllerCorePEQ.notify(payload, BEGIN_SREFB,
|
||||
command.getStart() - sc_time_stamp());
|
||||
break;
|
||||
case Command::SREFX:
|
||||
if(!Configuration::getInstance().BankwiseLogic)
|
||||
{
|
||||
controllerCorePEQ.notify(payload, END_SREF, command.getStart() - sc_time_stamp());
|
||||
}
|
||||
else
|
||||
controllerCorePEQ.notify(payload, END_SREFB, command.getStart() - sc_time_stamp());
|
||||
if (!Configuration::getInstance().BankwiseLogic) {
|
||||
controllerCorePEQ.notify(payload, END_SREF,
|
||||
command.getStart() - sc_time_stamp());
|
||||
} else
|
||||
controllerCorePEQ.notify(payload, END_SREFB,
|
||||
command.getStart() - sc_time_stamp());
|
||||
break;
|
||||
default:
|
||||
SC_REPORT_FATAL(0, "unsupported command was sent by controller");
|
||||
@@ -181,65 +178,61 @@ void Controller::send(const ScheduledCommand &command, tlm_generic_payload &payl
|
||||
}
|
||||
|
||||
//Trigger the next planned refresh or the power down mode on the DRAM
|
||||
void Controller::send(Trigger trigger, sc_time time, tlm_generic_payload &payload)
|
||||
void Controller::send(Trigger trigger, sc_time time,
|
||||
tlm_generic_payload &payload)
|
||||
{
|
||||
sc_assert(time >= sc_time_stamp());
|
||||
|
||||
sc_time delay = time - sc_time_stamp();
|
||||
if (trigger == Trigger::REFTrigger)
|
||||
{
|
||||
if (trigger == Trigger::REFTrigger) {
|
||||
controllerCorePEQ.notify(payload, REF_TRIGGER, delay);
|
||||
}
|
||||
else if (trigger == Trigger::PDNTrigger)
|
||||
{
|
||||
} else if (trigger == Trigger::PDNTrigger) {
|
||||
controllerCorePEQ.notify(payload, PDN_TRIGGER, delay);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
SC_REPORT_FATAL("controller wrapper", "unknown trigger");
|
||||
}
|
||||
}
|
||||
|
||||
void Controller::controllerCorePEQCallback(tlm_generic_payload &payload, const tlm_phase &phase)
|
||||
void Controller::controllerCorePEQCallback(tlm_generic_payload &payload,
|
||||
const tlm_phase &phase)
|
||||
{
|
||||
if (phase == REF_TRIGGER)
|
||||
{
|
||||
if (phase == REF_TRIGGER) {
|
||||
controllerCore->triggerRefresh(payload);
|
||||
}
|
||||
else if (phase == PDN_TRIGGER)
|
||||
{
|
||||
controllerCore->powerDownManager->sleep(DramExtension::getExtension(payload).getBank(),sc_time_stamp());
|
||||
}
|
||||
else
|
||||
{
|
||||
} else if (phase == PDN_TRIGGER) {
|
||||
controllerCore->powerDownManager->sleep(DramExtension::getExtension(
|
||||
payload).getBank(), sc_time_stamp());
|
||||
} else {
|
||||
Bank bank = DramExtension::getBank(payload);
|
||||
sendToDram(payload, phase, SC_ZERO_TIME);
|
||||
|
||||
if (phase == BEGIN_RD || phase == BEGIN_WR)
|
||||
{
|
||||
if (phase == BEGIN_RD || phase == BEGIN_WR) {
|
||||
scheduleNextFromScheduler(DramExtension::getBank(payload));
|
||||
}
|
||||
else if (phase == BEGIN_REFB)
|
||||
} else if (phase == BEGIN_REFB)
|
||||
printDebugMessage("Entering REFB on bank " + to_string(bank.ID()));
|
||||
else if (phase == BEGIN_REFA)
|
||||
printDebugMessage("Entering REFA");
|
||||
else if (containsPhase(phase, { BEGIN_PDNAB, BEGIN_PDNPB, BEGIN_SREFB }))
|
||||
printDebugMessage("Entering PowerDown " + phaseNameToString(phase) + " on bank " + to_string(bank.ID()));
|
||||
printDebugMessage("Entering PowerDown " + phaseNameToString(
|
||||
phase) + " on bank " + to_string(bank.ID()));
|
||||
else if (containsPhase(phase, { END_PDNAB, END_PDNPB, END_SREFB }))
|
||||
printDebugMessage("Leaving PowerDown " + phaseNameToString(phase) + " on bank " + to_string(bank.ID()));
|
||||
printDebugMessage("Leaving PowerDown " + phaseNameToString(
|
||||
phase) + " on bank " + to_string(bank.ID()));
|
||||
else if (containsPhase(phase, { BEGIN_PDNA, BEGIN_PDNP, BEGIN_SREF }))
|
||||
printDebugMessage("Entering PowerDown " + phaseNameToString(phase) + " on all banks");
|
||||
printDebugMessage("Entering PowerDown " + phaseNameToString(
|
||||
phase) + " on all banks");
|
||||
else if (containsPhase(phase, { END_PDNA, END_PDNP, END_SREF }))
|
||||
printDebugMessage("Leaving PowerDown " + phaseNameToString(phase) + " on all banks" );
|
||||
else if (containsPhase(phase, { BEGIN_RD, BEGIN_WR, BEGIN_ACT, BEGIN_PRE, BEGIN_PRE_ALL, BEGIN_RDA, BEGIN_WRA }))
|
||||
{
|
||||
printDebugMessage("Leaving PowerDown " + phaseNameToString(
|
||||
phase) + " on all banks" );
|
||||
else if (containsPhase(phase, { BEGIN_RD, BEGIN_WR, BEGIN_ACT, BEGIN_PRE, BEGIN_PRE_ALL, BEGIN_RDA, BEGIN_WRA })) {
|
||||
}
|
||||
else
|
||||
SC_REPORT_FATAL(0, "refreshTriggerPEQCallback queue in controller wrapper was triggered with unsupported phase");
|
||||
SC_REPORT_FATAL(0,
|
||||
"refreshTriggerPEQCallback queue in controller wrapper was triggered with unsupported phase");
|
||||
}
|
||||
}
|
||||
|
||||
tlm_sync_enum Controller::nb_transport_fw(tlm_generic_payload &payload, tlm_phase &phase, sc_time &fwDelay)
|
||||
tlm_sync_enum Controller::nb_transport_fw(tlm_generic_payload &payload,
|
||||
tlm_phase &phase, sc_time &fwDelay)
|
||||
{
|
||||
sc_time recTime;
|
||||
sc_time notDelay;
|
||||
@@ -251,31 +244,39 @@ tlm_sync_enum Controller::nb_transport_fw(tlm_generic_payload &payload, tlm_phas
|
||||
unsigned int row = DramExtension::getExtension(payload).getRow().ID();
|
||||
unsigned int col = DramExtension::getExtension(payload).getColumn().ID();
|
||||
|
||||
if (phase == BEGIN_REQ)
|
||||
{
|
||||
if (phase == BEGIN_REQ) {
|
||||
recTime = fwDelay + sc_time_stamp();
|
||||
notDelay = clkAlign(sc_time_stamp() + fwDelay) - (sc_time_stamp() + fwDelay) + Configuration::getInstance().memSpec.clk;
|
||||
notDelay = clkAlign(sc_time_stamp() + fwDelay) - (sc_time_stamp() + fwDelay) +
|
||||
Configuration::getInstance().memSpec.clk;
|
||||
|
||||
printDebugMessage("[fw] Recording " + phaseNameToString(phase) + " thread " + to_string(thr) + " channel " + to_string(ch) + " bank group " + to_string(bg) + " bank " + to_string(bank) + " row " + to_string(row) + " column " + to_string(col) + " at " + recTime.to_string() + " notification in " + notDelay.to_string());
|
||||
printDebugMessage("[fw] Recording " + phaseNameToString(
|
||||
phase) + " thread " + to_string(thr) + " channel " + to_string(
|
||||
ch) + " bank group " + to_string(bg) + " bank " + to_string(
|
||||
bank) + " row " + to_string(row) + " column " + to_string(
|
||||
col) + " at " + recTime.to_string() + " notification in " +
|
||||
notDelay.to_string());
|
||||
|
||||
tlmRecorder->recordPhase(payload, phase, recTime);
|
||||
frontendPEQ.notify(payload, phase, notDelay);
|
||||
|
||||
//Bandwidth IDLE
|
||||
if ((getTotalNumberOfPayloadsInSystem()== 0)&& idleState){
|
||||
if ((getTotalNumberOfPayloadsInSystem() == 0) && idleState) {
|
||||
endBandwidthIdleCollector();
|
||||
}
|
||||
}
|
||||
else if (phase == END_RESP)
|
||||
{
|
||||
} else if (phase == END_RESP) {
|
||||
|
||||
recTime = fwDelay + sc_time_stamp() + Configuration::getInstance().memSpec.clk;
|
||||
notDelay = clkAlign(sc_time_stamp() + fwDelay) - (sc_time_stamp() + fwDelay);
|
||||
|
||||
printDebugMessage("[fw] Recording " + phaseNameToString(phase) + " thread " + to_string(thr) + " channel " + to_string(ch) + " bank group " + to_string(bg) + " bank " + to_string(bank) + " row " + to_string(row) + " column " + to_string(col) + " at " + recTime.to_string() + " notification in " + notDelay.to_string());
|
||||
printDebugMessage("[fw] Recording " + phaseNameToString(
|
||||
phase) + " thread " + to_string(thr) + " channel " + to_string(
|
||||
ch) + " bank group " + to_string(bg) + " bank " + to_string(
|
||||
bank) + " row " + to_string(row) + " column " + to_string(
|
||||
col) + " at " + recTime.to_string() + " notification in " +
|
||||
notDelay.to_string());
|
||||
|
||||
// Badnwith IDLE
|
||||
if (getTotalNumberOfPayloadsInSystem()==1){
|
||||
if (getTotalNumberOfPayloadsInSystem() == 1) {
|
||||
startBandwidthIdleCollector();
|
||||
}
|
||||
|
||||
@@ -286,20 +287,21 @@ tlm_sync_enum Controller::nb_transport_fw(tlm_generic_payload &payload, tlm_phas
|
||||
return TLM_ACCEPTED;
|
||||
}
|
||||
|
||||
unsigned int Controller::transport_dbg(tlm::tlm_generic_payload& trans)
|
||||
unsigned int Controller::transport_dbg(tlm::tlm_generic_payload &trans)
|
||||
{
|
||||
return iSocket->transport_dbg(trans);
|
||||
}
|
||||
|
||||
void Controller::frontendPEQCallback(tlm_generic_payload &payload, const tlm_phase &phase)
|
||||
void Controller::frontendPEQCallback(tlm_generic_payload &payload,
|
||||
const tlm_phase &phase)
|
||||
{
|
||||
if (phase == BEGIN_REQ)
|
||||
{
|
||||
printDebugMessage(string("Payload in system: ") + to_string(getTotalNumberOfPayloadsInSystem()));
|
||||
if (phase == BEGIN_REQ) {
|
||||
printDebugMessage(string("Payload in system: ") + to_string(
|
||||
getTotalNumberOfPayloadsInSystem()));
|
||||
payload.acquire();
|
||||
payloadEntersSystem(payload);
|
||||
if (getTotalNumberOfPayloadsInSystem() > controllerCore->config.MaxNrOfTransactions)
|
||||
{
|
||||
if (getTotalNumberOfPayloadsInSystem() >
|
||||
controllerCore->config.MaxNrOfTransactions) {
|
||||
printDebugMessage("##Backpressure: Max number of transactions in system reached");
|
||||
backpressure = &payload;
|
||||
return;
|
||||
@@ -309,16 +311,11 @@ void Controller::frontendPEQCallback(tlm_generic_payload &payload, const tlm_pha
|
||||
|
||||
scheduler->schedule(&payload);
|
||||
scheduleNextFromScheduler(DramExtension::getExtension(payload).getBank());
|
||||
}
|
||||
else if (phase == PendingRequest)
|
||||
{
|
||||
// Schedule a pending request.
|
||||
scheduleNextFromScheduler(DramExtension::getExtension(payload).getBank());
|
||||
}
|
||||
else if (phase == END_RESP)
|
||||
{
|
||||
if (backpressure != NULL)
|
||||
{
|
||||
} else if (phase == PendingRequest) {
|
||||
// Schedule a pending request.
|
||||
scheduleNextFromScheduler(DramExtension::getExtension(payload).getBank());
|
||||
} else if (phase == END_RESP) {
|
||||
if (backpressure != NULL) {
|
||||
printDebugMessage("##Backpressure released");
|
||||
backpressure->set_response_status(tlm::TLM_OK_RESPONSE);
|
||||
sendToFrontend(*backpressure, END_REQ, SC_ZERO_TIME);
|
||||
@@ -330,10 +327,9 @@ void Controller::frontendPEQCallback(tlm_generic_payload &payload, const tlm_pha
|
||||
|
||||
payloadLeavesSystem(payload);
|
||||
payload.release();
|
||||
}
|
||||
else
|
||||
{
|
||||
SC_REPORT_FATAL(0, "Frontend PEQ event queue in controller wrapper was triggered with unknown phase");
|
||||
} else {
|
||||
SC_REPORT_FATAL(0,
|
||||
"Frontend PEQ event queue in controller wrapper was triggered with unknown phase");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,13 +337,14 @@ void Controller::payloadEntersSystem(tlm_generic_payload &payload)
|
||||
{
|
||||
Bank bank = DramExtension::getExtension(payload).getBank();
|
||||
printDebugMessage(
|
||||
"Payload enters system on bank " + to_string(bank.ID()) + ". Total number of payloads in Controller: "
|
||||
+ to_string(getTotalNumberOfPayloadsInSystem()));
|
||||
"Payload enters system on bank " + to_string(bank.ID()) +
|
||||
". Total number of payloads in Controller: "
|
||||
+ to_string(getTotalNumberOfPayloadsInSystem()));
|
||||
numberOfPayloadsInSystem[bank]++;
|
||||
// Set Start Time for Simulation
|
||||
if (startTimeSet == false){
|
||||
if (startTimeSet == false) {
|
||||
printDebugMessage("Simulation Timer Start");
|
||||
startTime = sc_time_stamp()-Configuration::getInstance().memSpec.clk;
|
||||
startTime = sc_time_stamp() - Configuration::getInstance().memSpec.clk;
|
||||
startTimeSet = true;
|
||||
}
|
||||
}
|
||||
@@ -357,16 +354,16 @@ void Controller::payloadLeavesSystem(tlm_generic_payload &payload)
|
||||
Bank bank = DramExtension::getExtension(payload).getBank();
|
||||
numberOfPayloadsInSystem[bank]--;
|
||||
printDebugMessage(
|
||||
"Payload left system on bank " + to_string(bank.ID()) + ". Total number of payloads in Controller: "
|
||||
+ to_string(getTotalNumberOfPayloadsInSystem()));
|
||||
"Payload left system on bank " + to_string(bank.ID()) +
|
||||
". Total number of payloads in Controller: "
|
||||
+ to_string(getTotalNumberOfPayloadsInSystem()));
|
||||
controllerCore->powerDownManager->triggerSleep(bank, sc_time_stamp());
|
||||
}
|
||||
|
||||
unsigned int Controller::getTotalNumberOfPayloadsInSystem()
|
||||
{
|
||||
unsigned int sum = 0;
|
||||
for (Bank bank : controllerCore->getBanks())
|
||||
{
|
||||
for (Bank bank : controllerCore->getBanks()) {
|
||||
sum += numberOfPayloadsInSystem[bank];
|
||||
}
|
||||
return sum;
|
||||
@@ -375,27 +372,26 @@ unsigned int Controller::getTotalNumberOfPayloadsInSystem()
|
||||
void Controller::scheduleNextFromScheduler(Bank bank)
|
||||
{
|
||||
|
||||
if(controllerCore->bankIsBusy(bank))
|
||||
{
|
||||
if (controllerCore->bankIsBusy(bank)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool rescheduled = true;
|
||||
pair<Command, tlm::tlm_generic_payload*> nextRequest = scheduler->getNextRequest(bank);
|
||||
if(nextRequest.second != NULL)
|
||||
{
|
||||
controllerCore->powerDownManager->wakeUp(DramExtension::getExtension(nextRequest.second).getBank(), sc_time_stamp());
|
||||
pair<Command, tlm::tlm_generic_payload *> nextRequest =
|
||||
scheduler->getNextRequest(bank);
|
||||
if (nextRequest.second != NULL) {
|
||||
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 [" + commandToString(nextRequest.first) + "]");
|
||||
}
|
||||
else
|
||||
{
|
||||
gp* pendingRequest = scheduler->getPendingRequest(bank);
|
||||
if (pendingRequest != NULL)
|
||||
{
|
||||
rescheduled = true;
|
||||
frontendPEQ.notify(*(pendingRequest), PendingRequest, Configuration::getInstance().memSpec.clk);
|
||||
}
|
||||
printDebugMessage("\t-> Next payload was scheduled by core [" + commandToString(
|
||||
nextRequest.first) + "]");
|
||||
} else {
|
||||
gp *pendingRequest = scheduler->getPendingRequest(bank);
|
||||
if (pendingRequest != NULL) {
|
||||
rescheduled = true;
|
||||
frontendPEQ.notify(*(pendingRequest), PendingRequest,
|
||||
Configuration::getInstance().memSpec.clk);
|
||||
}
|
||||
}
|
||||
|
||||
queue<Bank> blocked;
|
||||
@@ -403,24 +399,23 @@ void Controller::scheduleNextFromScheduler(Bank bank)
|
||||
bank = blockedRequests.front();
|
||||
blockedRequests.pop();
|
||||
|
||||
pair<Command, tlm::tlm_generic_payload*> nextRequest = scheduler->getNextRequest(bank);
|
||||
pair<Command, tlm::tlm_generic_payload *> nextRequest =
|
||||
scheduler->getNextRequest(bank);
|
||||
if (nextRequest.second != NULL) {
|
||||
controllerCore->powerDownManager->wakeUp(DramExtension::getExtension(nextRequest.second).getBank(), sc_time_stamp());
|
||||
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 [" + commandToString(nextRequest.first) + "] (unblocked)");
|
||||
}
|
||||
else
|
||||
{
|
||||
gp* pendingRequest = scheduler->getPendingRequest(bank);
|
||||
if(pendingRequest != NULL)
|
||||
{
|
||||
printDebugMessage("\t-> Next payload was scheduled by core [" + commandToString(
|
||||
nextRequest.first) + "] (unblocked)");
|
||||
} else {
|
||||
gp *pendingRequest = scheduler->getPendingRequest(bank);
|
||||
if (pendingRequest != NULL) {
|
||||
//Pending request
|
||||
if(!rescheduled)
|
||||
{
|
||||
if (!rescheduled) {
|
||||
rescheduled = true;
|
||||
frontendPEQ.notify(*(pendingRequest), PendingRequest, Configuration::getInstance().memSpec.clk);
|
||||
}
|
||||
else
|
||||
frontendPEQ.notify(*(pendingRequest), PendingRequest,
|
||||
Configuration::getInstance().memSpec.clk);
|
||||
} else
|
||||
blocked.push(bank);
|
||||
}
|
||||
}
|
||||
@@ -428,14 +423,16 @@ void Controller::scheduleNextFromScheduler(Bank bank)
|
||||
blockedRequests = blocked;
|
||||
}
|
||||
|
||||
void Controller::sendToFrontend(tlm_generic_payload &payload, const tlm_phase &phase, const sc_time &delay)
|
||||
void Controller::sendToFrontend(tlm_generic_payload &payload,
|
||||
const tlm_phase &phase, const sc_time &delay)
|
||||
{
|
||||
tlm_phase TPhase = phase;
|
||||
sc_time TDelay = delay;
|
||||
tSocket->nb_transport_bw(payload, TPhase, TDelay);
|
||||
}
|
||||
|
||||
tlm_sync_enum Controller::nb_transport_bw(tlm_generic_payload &payload, tlm_phase &phase, sc_time &bwDelay)
|
||||
tlm_sync_enum Controller::nb_transport_bw(tlm_generic_payload &payload,
|
||||
tlm_phase &phase, sc_time &bwDelay)
|
||||
{
|
||||
sc_time recTime = bwDelay + sc_time_stamp();
|
||||
sc_time notDelay = bwDelay;
|
||||
@@ -447,7 +444,12 @@ tlm_sync_enum Controller::nb_transport_bw(tlm_generic_payload &payload, tlm_phas
|
||||
unsigned int row = DramExtension::getExtension(payload).getRow().ID();
|
||||
unsigned int col = DramExtension::getExtension(payload).getColumn().ID();
|
||||
|
||||
printDebugMessage("[bw] Recording " + phaseNameToString(phase) + " thread " + to_string(thr) + " channel " + to_string(ch) + " bank group " + to_string(bg) + " bank " + to_string(bank) + " row " + to_string(row) + " column " + to_string(col) + " at " + recTime.to_string() + " notification in " + notDelay.to_string());
|
||||
printDebugMessage("[bw] Recording " + phaseNameToString(
|
||||
phase) + " thread " + to_string(thr) + " channel " + to_string(
|
||||
ch) + " bank group " + to_string(bg) + " bank " + to_string(
|
||||
bank) + " row " + to_string(row) + " column " + to_string(
|
||||
col) + " at " + recTime.to_string() + " notification in " +
|
||||
notDelay.to_string());
|
||||
|
||||
dramPEQ.notify(payload, phase, notDelay);
|
||||
tlmRecorder->recordPhase(payload, phase, recTime);
|
||||
@@ -455,71 +457,57 @@ tlm_sync_enum Controller::nb_transport_bw(tlm_generic_payload &payload, tlm_phas
|
||||
return TLM_ACCEPTED;
|
||||
}
|
||||
|
||||
void Controller::dramPEQCallback(tlm_generic_payload &payload, const tlm_phase &phase)
|
||||
void Controller::dramPEQCallback(tlm_generic_payload &payload,
|
||||
const tlm_phase &phase)
|
||||
{
|
||||
Bank bank = DramExtension::getExtension(payload).getBank();
|
||||
printDebugMessage("Received " + phaseNameToString(phase) + " on bank " + to_string(bank.ID()) + " from DRAM");
|
||||
printDebugMessage("Received " + phaseNameToString(phase) + " on bank " +
|
||||
to_string(bank.ID()) + " from DRAM");
|
||||
|
||||
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)
|
||||
{
|
||||
} else if (phase == END_RDA || phase == END_WRA) {
|
||||
sendToFrontend(payload, BEGIN_RESP, SC_ZERO_TIME);
|
||||
scheduleNextFromScheduler(bank);
|
||||
}
|
||||
else if (phase == END_REFA)
|
||||
{
|
||||
} else if (phase == END_REFA) {
|
||||
printDebugMessage("Finished auto refresh on all banks ");
|
||||
|
||||
bool sleepy = true;
|
||||
for(Bank bank : controllerCore->getBanks())
|
||||
{
|
||||
if(numberOfPayloadsInSystem[bank] != 0)
|
||||
{
|
||||
for (Bank bank : controllerCore->getBanks()) {
|
||||
if (numberOfPayloadsInSystem[bank] != 0) {
|
||||
sleepy = false;
|
||||
scheduleNextFromScheduler(bank);
|
||||
}
|
||||
}
|
||||
|
||||
if(sleepy == true)
|
||||
{
|
||||
controllerCore->powerDownManager->sleep(0,sc_time_stamp());
|
||||
if (sleepy == true) {
|
||||
controllerCore->powerDownManager->sleep(0, sc_time_stamp());
|
||||
}
|
||||
}
|
||||
else if(phase == END_REFB)
|
||||
{
|
||||
} 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
|
||||
{
|
||||
if (numberOfPayloadsInSystem[bank] == 0) {
|
||||
controllerCore->powerDownManager->sleep(bank, sc_time_stamp());
|
||||
} else {
|
||||
scheduleNextFromScheduler(bank);
|
||||
}
|
||||
scheduleNextFromScheduler(bank);
|
||||
}
|
||||
else if (containsPhase(phase, { END_PRE, END_ACT }))
|
||||
{
|
||||
} else if (containsPhase(phase, { END_PRE, END_ACT })) {
|
||||
scheduleNextFromScheduler(bank);
|
||||
}
|
||||
else if(phase == END_PRE_ALL)
|
||||
{
|
||||
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
|
||||
{
|
||||
string str = string("dramPEQCallback queue in controller wrapper was triggered with unsupported phase ")
|
||||
+ phaseNameToString(phase);
|
||||
} else {
|
||||
string str =
|
||||
string("dramPEQCallback queue in controller wrapper was triggered with unsupported phase ")
|
||||
+ phaseNameToString(phase);
|
||||
SC_REPORT_FATAL(0, str.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void Controller::sendToDram(tlm_generic_payload &payload, const tlm_phase &phase, const sc_time &delay)
|
||||
void Controller::sendToDram(tlm_generic_payload &payload,
|
||||
const tlm_phase &phase, const sc_time &delay)
|
||||
{
|
||||
tlm_phase TPhase = phase;
|
||||
sc_time TDelay = delay;
|
||||
@@ -533,8 +521,7 @@ void Controller::printDebugMessage(string message)
|
||||
|
||||
bool Controller::containsPhase(tlm_phase phase, std::vector<tlm_phase> phases)
|
||||
{
|
||||
for (tlm_phase p : phases)
|
||||
{
|
||||
for (tlm_phase p : phases) {
|
||||
if (p == phase)
|
||||
return true;
|
||||
}
|
||||
@@ -548,15 +535,11 @@ void Controller::end_of_simulation()
|
||||
|
||||
void Controller::terminateSimulation()
|
||||
{
|
||||
if(Configuration::getInstance().BankwiseLogic)
|
||||
{
|
||||
for (Bank bank : controllerCore->getBanks())
|
||||
{
|
||||
if (Configuration::getInstance().BankwiseLogic) {
|
||||
for (Bank bank : controllerCore->getBanks()) {
|
||||
controllerCore->powerDownManager->wakeUp(bank, clkAlign(sc_time_stamp()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
controllerCore->powerDownManager->wakeUp(0, clkAlign(sc_time_stamp()));
|
||||
}
|
||||
|
||||
@@ -574,24 +557,25 @@ void Controller::startBandwidthIdleCollector()
|
||||
void Controller::endBandwidthIdleCollector()
|
||||
{
|
||||
printDebugMessage("IDLE End");
|
||||
idleTime += sc_time_stamp()-idleStart+ Configuration::getInstance().memSpec.clk;
|
||||
idleTime += sc_time_stamp() - idleStart +
|
||||
Configuration::getInstance().memSpec.clk;
|
||||
idleState = false;
|
||||
}
|
||||
|
||||
sc_time Controller::getIdleTime()
|
||||
{
|
||||
printDebugMessage("IDLE Time: "+idleTime.to_string());
|
||||
printDebugMessage("IDLE Time: " + idleTime.to_string());
|
||||
return idleTime;
|
||||
}
|
||||
|
||||
sc_time Controller::getEndTime()
|
||||
{
|
||||
printDebugMessage("End Time: "+endTime.to_string());
|
||||
printDebugMessage("End Time: " + endTime.to_string());
|
||||
return endTime;
|
||||
}
|
||||
|
||||
sc_time Controller::getStartTime()
|
||||
{
|
||||
printDebugMessage("Start Time: "+startTime.to_string());
|
||||
printDebugMessage("Start Time: " + startTime.to_string());
|
||||
return startTime;
|
||||
}
|
||||
|
||||
@@ -81,7 +81,10 @@ class Controller: public sc_module, public IController
|
||||
{
|
||||
public:
|
||||
Controller(sc_module_name /*name*/, TlmRecorder *rec) :
|
||||
frontendPEQ(this, &Controller::frontendPEQCallback), dramPEQ(this, &Controller::dramPEQCallback), controllerCorePEQ(this, &Controller::controllerCorePEQCallback), debugManager(DebugManager::getInstance()), tlmRecorder(rec)
|
||||
frontendPEQ(this, &Controller::frontendPEQCallback), dramPEQ(this,
|
||||
&Controller::dramPEQCallback), controllerCorePEQ(this,
|
||||
&Controller::controllerCorePEQCallback),
|
||||
debugManager(DebugManager::getInstance()), tlmRecorder(rec)
|
||||
{
|
||||
controllerCore = new ControllerCore("core", *this, numberOfPayloadsInSystem);
|
||||
buildScheduler();
|
||||
@@ -103,51 +106,61 @@ public:
|
||||
sc_time getStartTime();
|
||||
|
||||
// ------- CONTROLLER CORE ---------
|
||||
virtual void send(const ScheduledCommand& command, tlm_generic_payload& payload) override;
|
||||
virtual void send(Trigger trigger, sc_time time, tlm_generic_payload& payload) override;
|
||||
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> iSocket;
|
||||
tlm_utils::simple_target_socket<Controller> tSocket;
|
||||
unsigned int getTotalNumberOfPayloadsInSystem();
|
||||
void scheduleNextFromScheduler(Bank bank) override;
|
||||
|
||||
static unsigned int ControllerThreadId() {return controllerThreadId;}
|
||||
static unsigned int ControllerThreadId()
|
||||
{
|
||||
return controllerThreadId;
|
||||
}
|
||||
|
||||
private:
|
||||
void buildScheduler();
|
||||
void payloadEntersSystem(tlm_generic_payload& payload);
|
||||
void payloadLeavesSystem(tlm_generic_payload& payload);
|
||||
void payloadEntersSystem(tlm_generic_payload &payload);
|
||||
void payloadLeavesSystem(tlm_generic_payload &payload);
|
||||
|
||||
// --- FRONTEND ------
|
||||
tlm_sync_enum nb_transport_fw(tlm_generic_payload& payload, tlm_phase& phase, sc_time& fwDelay);
|
||||
virtual unsigned int transport_dbg(tlm::tlm_generic_payload& trans);
|
||||
void frontendPEQCallback(tlm_generic_payload& payload, const tlm_phase& phase);
|
||||
void sendToFrontend(tlm_generic_payload& payload, const tlm_phase& phase, const sc_time& delay);
|
||||
tlm_sync_enum nb_transport_fw(tlm_generic_payload &payload, tlm_phase &phase,
|
||||
sc_time &fwDelay);
|
||||
virtual unsigned int transport_dbg(tlm::tlm_generic_payload &trans);
|
||||
void frontendPEQCallback(tlm_generic_payload &payload, const tlm_phase &phase);
|
||||
void sendToFrontend(tlm_generic_payload &payload, const tlm_phase &phase,
|
||||
const sc_time &delay);
|
||||
|
||||
// --- DRAM ------
|
||||
tlm_sync_enum nb_transport_bw(tlm_generic_payload& payload, tlm_phase& phase, sc_time& bwDelay);
|
||||
void dramPEQCallback(tlm_generic_payload& payload, const tlm_phase& phase);
|
||||
void sendToDram(tlm_generic_payload& payload, const tlm_phase& phase, const sc_time& delay);
|
||||
tlm_sync_enum nb_transport_bw(tlm_generic_payload &payload, tlm_phase &phase,
|
||||
sc_time &bwDelay);
|
||||
void dramPEQCallback(tlm_generic_payload &payload, const tlm_phase &phase);
|
||||
void sendToDram(tlm_generic_payload &payload, const tlm_phase &phase,
|
||||
const sc_time &delay);
|
||||
|
||||
// ------- CONTROLLER CORE ---------
|
||||
void controllerCorePEQCallback(tlm_generic_payload& payload, const tlm_phase& phase);
|
||||
void controllerCorePEQCallback(tlm_generic_payload &payload,
|
||||
const tlm_phase &phase);
|
||||
|
||||
// Helpers TODO move them
|
||||
void printDebugMessage(string message);
|
||||
bool containsPhase(tlm_phase phase, std::vector<tlm_phase> phases);
|
||||
|
||||
ControllerCore* controllerCore;
|
||||
ControllerCore *controllerCore;
|
||||
//Scheduler* scheduler;
|
||||
IScheduler* scheduler;
|
||||
IScheduler *scheduler;
|
||||
std::map<Bank, int> numberOfPayloadsInSystem;
|
||||
std::vector<gp* > refreshCollisionRequets;
|
||||
tlm::tlm_generic_payload* backpressure = NULL;
|
||||
std::vector<gp * > refreshCollisionRequets;
|
||||
tlm::tlm_generic_payload *backpressure = NULL;
|
||||
|
||||
tlm_utils::peq_with_cb_and_phase<Controller> frontendPEQ;
|
||||
tlm_utils::peq_with_cb_and_phase<Controller> dramPEQ;
|
||||
tlm_utils::peq_with_cb_and_phase<Controller> controllerCorePEQ;
|
||||
|
||||
DebugManager& debugManager;
|
||||
DebugManager &debugManager;
|
||||
TlmRecorder *tlmRecorder;
|
||||
|
||||
// Bandwidth realted:
|
||||
|
||||
@@ -41,7 +41,8 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
const ScheduledCommand ControllerState::getLastCommand(Command command, Bank bank) //TODO const reference? and make const
|
||||
const ScheduledCommand ControllerState::getLastCommand(Command command,
|
||||
Bank bank) //TODO const reference? and make const
|
||||
{
|
||||
return lastScheduledByCommandAndBank[command][bank];
|
||||
}
|
||||
@@ -50,8 +51,7 @@ const ScheduledCommand ControllerState::getLastCommand(Command command)
|
||||
{
|
||||
ScheduledCommand max;
|
||||
|
||||
for (unsigned int i = 0; i < config->memSpec.NumberOfBanks; ++i)
|
||||
{
|
||||
for (unsigned int i = 0; i < config->memSpec.NumberOfBanks; ++i) {
|
||||
ScheduledCommand current = getLastCommand(command, Bank(i));
|
||||
if (current.getStart() > max.getStart())
|
||||
max = current;
|
||||
@@ -64,17 +64,16 @@ const ScheduledCommand ControllerState::getLastScheduledCommand()
|
||||
{
|
||||
ScheduledCommand lastCommand;
|
||||
|
||||
for(Command cmd : getAllCommands())
|
||||
{
|
||||
for(Bank bank : Configuration::getInstance().memSpec.getBanks())
|
||||
{
|
||||
ScheduledCommand& current = lastScheduledByCommandAndBank[cmd][bank];
|
||||
for (Command cmd : getAllCommands()) {
|
||||
for (Bank bank : Configuration::getInstance().memSpec.getBanks()) {
|
||||
ScheduledCommand ¤t = lastScheduledByCommandAndBank[cmd][bank];
|
||||
if (current.getStart() > lastCommand.getStart())
|
||||
lastCommand = current;
|
||||
}
|
||||
}
|
||||
|
||||
printDebugMessage("Last scheduled command was " + commandToString(lastCommand.getCommand()));
|
||||
printDebugMessage("Last scheduled command was " + commandToString(
|
||||
lastCommand.getCommand()));
|
||||
|
||||
return lastCommand;
|
||||
}
|
||||
@@ -83,27 +82,29 @@ const ScheduledCommand ControllerState::getLastScheduledCommand(Bank bank)
|
||||
{
|
||||
ScheduledCommand lastCommand;
|
||||
|
||||
for(Command cmd : getAllCommands())
|
||||
{
|
||||
ScheduledCommand& current = lastScheduledByCommandAndBank[cmd][bank];
|
||||
for (Command cmd : getAllCommands()) {
|
||||
ScheduledCommand ¤t = lastScheduledByCommandAndBank[cmd][bank];
|
||||
if (current.getStart() > lastCommand.getStart())
|
||||
lastCommand = current;
|
||||
}
|
||||
|
||||
printDebugMessage("Last scheduled command on bank " + to_string(bank.ID()) + " was " + commandToString(lastCommand.getCommand()));
|
||||
printDebugMessage("Last scheduled command on bank " + to_string(
|
||||
bank.ID()) + " was " + commandToString(lastCommand.getCommand()));
|
||||
|
||||
return lastCommand;
|
||||
}
|
||||
|
||||
void ControllerState::change(const ScheduledCommand& scheduledCommand)
|
||||
void ControllerState::change(const ScheduledCommand &scheduledCommand)
|
||||
{
|
||||
bus.blockSlot(scheduledCommand.getStart());
|
||||
|
||||
printDebugMessage("Changing state on bank " + to_string(scheduledCommand.getBank().ID()) + " command is " + commandToString(scheduledCommand.getCommand()));
|
||||
lastScheduledByCommandAndBank[scheduledCommand.getCommand()][scheduledCommand.getBank()] = scheduledCommand;
|
||||
printDebugMessage("Changing state on bank " + to_string(
|
||||
scheduledCommand.getBank().ID()) + " command is " + commandToString(
|
||||
scheduledCommand.getCommand()));
|
||||
lastScheduledByCommandAndBank[scheduledCommand.getCommand()][scheduledCommand.getBank()]
|
||||
= scheduledCommand;
|
||||
|
||||
switch (scheduledCommand.getCommand())
|
||||
{
|
||||
switch (scheduledCommand.getCommand()) {
|
||||
case Command::Read:
|
||||
lastDataStrobeCommands.emplace_back(scheduledCommand);
|
||||
break;
|
||||
@@ -121,7 +122,8 @@ void ControllerState::change(const ScheduledCommand& scheduledCommand)
|
||||
case Command::AutoRefresh:
|
||||
break;
|
||||
case Command::Activate:
|
||||
rowBufferStates->openRowInRowBuffer(scheduledCommand.getBank(), scheduledCommand.getRow());
|
||||
rowBufferStates->openRowInRowBuffer(scheduledCommand.getBank(),
|
||||
scheduledCommand.getRow());
|
||||
lastActivates.emplace(scheduledCommand.getStart(), scheduledCommand);
|
||||
break;
|
||||
case Command::Precharge:
|
||||
@@ -142,18 +144,19 @@ void ControllerState::cleanUp(sc_time time)
|
||||
{
|
||||
bus.cleanUpSlots(time);
|
||||
vector<ScheduledCommand> tmp;
|
||||
for(ScheduledCommand& command: lastDataStrobeCommands)
|
||||
{
|
||||
if(command.getEnd() >= time || getDistance(command.getEnd(), time) <= config->memSpec.tDataStrobeHistory())
|
||||
for (ScheduledCommand &command : lastDataStrobeCommands) {
|
||||
if (command.getEnd() >= time
|
||||
|| getDistance(command.getEnd(), time) <= config->memSpec.tDataStrobeHistory())
|
||||
tmp.push_back(command);
|
||||
}
|
||||
lastDataStrobeCommands = tmp;
|
||||
if(time >= config->memSpec.tActHistory())
|
||||
lastActivates.erase(lastActivates.begin(), lastActivates.lower_bound(time - config->memSpec.tActHistory()));
|
||||
if (time >= config->memSpec.tActHistory())
|
||||
lastActivates.erase(lastActivates.begin(),
|
||||
lastActivates.lower_bound(time - config->memSpec.tActHistory()));
|
||||
}
|
||||
|
||||
void ControllerState::printDebugMessage(std::string message)
|
||||
{
|
||||
DebugManager::getInstance().printDebugMessage(ownerName, message);
|
||||
DebugManager::getInstance().printDebugMessage(ownerName, message);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,24 +48,27 @@
|
||||
class ControllerState
|
||||
{
|
||||
public:
|
||||
ControllerState(std::string ownerName, Configuration *config) : bus(config->memSpec.clk), ownerName(ownerName), config(config)
|
||||
ControllerState(std::string ownerName,
|
||||
Configuration *config) : bus(config->memSpec.clk), ownerName(ownerName),
|
||||
config(config)
|
||||
{
|
||||
rowBufferStates = new RowBufferState(ownerName);
|
||||
rowBufferStates = new RowBufferState(ownerName);
|
||||
}
|
||||
virtual ~ControllerState(){}
|
||||
virtual ~ControllerState() {}
|
||||
|
||||
const ScheduledCommand getLastCommand(Command command, Bank bank);
|
||||
const ScheduledCommand getLastCommand(Command command);
|
||||
const ScheduledCommand getLastScheduledCommand(Bank bank);
|
||||
const ScheduledCommand getLastScheduledCommand();
|
||||
|
||||
void change(const ScheduledCommand& scheduledCommand);
|
||||
void change(const ScheduledCommand &scheduledCommand);
|
||||
void cleanUp(sc_time time);
|
||||
|
||||
RowBufferState *rowBufferStates;
|
||||
|
||||
//used by the various checkers
|
||||
std::map<Command, std::map<Bank, ScheduledCommand> > lastScheduledByCommandAndBank;
|
||||
std::map<Command, std::map<Bank, ScheduledCommand> >
|
||||
lastScheduledByCommandAndBank;
|
||||
std::map<Command, ScheduledCommand> lastScheduledByCommand;
|
||||
std::map<Bank, ScheduledCommand> lastScheduledByBank;
|
||||
ScheduledCommand lastScheduled;
|
||||
@@ -76,7 +79,7 @@ public:
|
||||
|
||||
private:
|
||||
std::string ownerName;
|
||||
Configuration* config;
|
||||
Configuration *config;
|
||||
void printDebugMessage(std::string message);
|
||||
};
|
||||
|
||||
|
||||
@@ -51,8 +51,10 @@ 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 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;
|
||||
|
||||
std::queue<Bank> blockedRequests;
|
||||
|
||||
@@ -43,7 +43,7 @@ using namespace std;
|
||||
|
||||
RowBufferState::RowBufferState(std::string ownerName) : ownerName(ownerName)
|
||||
{
|
||||
closeAllRowBuffers();
|
||||
closeAllRowBuffers();
|
||||
}
|
||||
|
||||
RowBufferState::~RowBufferState()
|
||||
@@ -52,31 +52,33 @@ RowBufferState::~RowBufferState()
|
||||
|
||||
bool RowBufferState::rowBufferIsOpen(Bank bank) const
|
||||
{
|
||||
return getElementFromMap(rowsInRowBuffers,bank) != Row::NO_ROW;
|
||||
return getElementFromMap(rowsInRowBuffers, bank) != Row::NO_ROW;
|
||||
}
|
||||
|
||||
Row RowBufferState::getRowInRowBuffer(Bank bank) const
|
||||
{
|
||||
return getElementFromMap(rowsInRowBuffers,bank);
|
||||
return getElementFromMap(rowsInRowBuffers, bank);
|
||||
}
|
||||
|
||||
void RowBufferState::openRowInRowBuffer(Bank bank,Row row)
|
||||
void RowBufferState::openRowInRowBuffer(Bank bank, Row row)
|
||||
{
|
||||
printDebugMessage("Row buffer for bank " + to_string(bank.ID()) + " is now open");
|
||||
printDebugMessage("Row buffer for bank " + to_string(bank.ID()) +
|
||||
" is now open");
|
||||
rowsInRowBuffers[bank] = row;
|
||||
}
|
||||
|
||||
void RowBufferState::closeRowBuffer(Bank bank)
|
||||
{
|
||||
printDebugMessage("Row buffer for bank " + to_string(bank.ID()) + " is now closed");
|
||||
printDebugMessage("Row buffer for bank " + to_string(bank.ID()) +
|
||||
" is now closed");
|
||||
rowsInRowBuffers[bank] = Row::NO_ROW;
|
||||
}
|
||||
|
||||
bool RowBufferState::allRowBuffersAreClosed() const
|
||||
{
|
||||
for(unsigned int i=0; i<Configuration::getInstance().memSpec.NumberOfBanks;++i)
|
||||
{
|
||||
if(rowBufferIsOpen(Bank(i)))
|
||||
for (unsigned int i = 0; i < Configuration::getInstance().memSpec.NumberOfBanks;
|
||||
++i) {
|
||||
if (rowBufferIsOpen(Bank(i)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -84,14 +86,14 @@ bool RowBufferState::allRowBuffersAreClosed() const
|
||||
|
||||
void RowBufferState::closeAllRowBuffers()
|
||||
{
|
||||
for(unsigned int i=0; i<Configuration::getInstance().memSpec.NumberOfBanks;++i)
|
||||
{
|
||||
for (unsigned int i = 0; i < Configuration::getInstance().memSpec.NumberOfBanks;
|
||||
++i) {
|
||||
rowsInRowBuffers[Bank(i)] = Row::NO_ROW;
|
||||
}
|
||||
}
|
||||
|
||||
void RowBufferState::printDebugMessage(std::string message)
|
||||
{
|
||||
DebugManager::getInstance().printDebugMessage(ownerName, message);
|
||||
DebugManager::getInstance().printDebugMessage(ownerName, message);
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,8 @@
|
||||
#include <map>
|
||||
#include "../common/dramExtension.h"
|
||||
|
||||
class RowBufferState {
|
||||
class RowBufferState
|
||||
{
|
||||
public:
|
||||
RowBufferState(std::string ownerName);
|
||||
virtual ~RowBufferState();
|
||||
@@ -55,7 +56,7 @@ public:
|
||||
|
||||
private:
|
||||
std::string ownerName;
|
||||
std::map<Bank,Row> rowsInRowBuffers;
|
||||
std::map<Bank, Row> rowsInRowBuffers;
|
||||
void printDebugMessage(std::string message);
|
||||
};
|
||||
|
||||
|
||||
@@ -57,8 +57,10 @@
|
||||
#include "powerdown/NoPowerDown.h"
|
||||
#include "../../common/DebugManager.h"
|
||||
|
||||
ControllerCore::ControllerCore(sc_module_name /*name*/, IController& wrapperConnector, std::map<Bank, int>& numberOfPayloads) :
|
||||
config(Configuration::getInstance()), controller(wrapperConnector), numberOfPayloads(numberOfPayloads), commandChecker()
|
||||
ControllerCore::ControllerCore(sc_module_name /*name*/,
|
||||
IController &wrapperConnector, std::map<Bank, int> &numberOfPayloads) :
|
||||
config(Configuration::getInstance()), controller(wrapperConnector),
|
||||
numberOfPayloads(numberOfPayloads), commandChecker()
|
||||
{
|
||||
state = new ControllerState(name(), &config);
|
||||
|
||||
@@ -78,36 +80,28 @@ ControllerCore::ControllerCore(sc_module_name /*name*/, IController& wrapperConn
|
||||
commandChecker[Command::PDNPX] = commandChecker[Command::PDNA];
|
||||
commandChecker[Command::SREFX] = commandChecker[Command::PDNA];
|
||||
|
||||
if (config.BankwiseLogic)
|
||||
{
|
||||
if (config.BankwiseLogic) {
|
||||
refreshManager = new RefreshManagerBankwise("refManagerBw", *this);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
refreshManager = new RefreshManager("refManager", *this);
|
||||
}
|
||||
|
||||
if(config.PowerDownMode == EPowerDownMode::Staggered)
|
||||
{
|
||||
if (config.PowerDownMode == EPowerDownMode::Staggered) {
|
||||
if (config.BankwiseLogic)
|
||||
powerDownManager = new PowerDownManagerBankwise("pdnManagerBw", *this);
|
||||
else
|
||||
powerDownManager = new PowerDownManager("pdnManager", *this);
|
||||
}
|
||||
else if(config.PowerDownMode == EPowerDownMode::TimeoutPDN || config.PowerDownMode == EPowerDownMode::TimeoutSREF)
|
||||
{
|
||||
} else if (config.PowerDownMode == EPowerDownMode::TimeoutPDN
|
||||
|| config.PowerDownMode == EPowerDownMode::TimeoutSREF) {
|
||||
if (config.BankwiseLogic)
|
||||
powerDownManager = new PowerDownManagerTimeoutBankwise("pdnManagerBw", *this);
|
||||
else
|
||||
powerDownManager = new PowerDownManagerTimeout("pdnManager", *this);
|
||||
}
|
||||
else if(config.PowerDownMode == EPowerDownMode::NoPowerDown)
|
||||
{
|
||||
} else if (config.PowerDownMode == EPowerDownMode::NoPowerDown) {
|
||||
powerDownManager = new NoPowerDown();
|
||||
}
|
||||
else
|
||||
{
|
||||
SC_REPORT_FATAL(0, "Unsupported powerdown mode in constructor of controller core");
|
||||
} else {
|
||||
SC_REPORT_FATAL(0,
|
||||
"Unsupported powerdown mode in constructor of controller core");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +119,7 @@ ControllerCore::~ControllerCore()
|
||||
delete state;
|
||||
}
|
||||
|
||||
void ControllerCore::triggerRefresh(tlm::tlm_generic_payload& payload)
|
||||
void ControllerCore::triggerRefresh(tlm::tlm_generic_payload &payload)
|
||||
{
|
||||
/* Refresh can be disabled for tests purpose */
|
||||
if (config.ControllerCoreDisableRefresh == false) {
|
||||
@@ -134,28 +128,27 @@ void ControllerCore::triggerRefresh(tlm::tlm_generic_payload& payload)
|
||||
|
||||
state->cleanUp(time);
|
||||
|
||||
if (!refreshManager->isInvalidated(payload, time) && !powerDownManager->isInSelfRefresh(bank))
|
||||
{
|
||||
if (!refreshManager->isInvalidated(payload, time)
|
||||
&& !powerDownManager->isInSelfRefresh(bank)) {
|
||||
printDebugMessage("Triggering refresh on bank " + to_string(bank.ID()));
|
||||
powerDownManager->wakeUpForRefresh(bank, time); //expects PDNA and PDNP to exit without delay
|
||||
powerDownManager->wakeUpForRefresh(bank,
|
||||
time); //expects PDNA and PDNP to exit without delay
|
||||
bool pdnpToSrefTransition = false;
|
||||
if (config.PowerDownMode == EPowerDownMode::Staggered)
|
||||
{
|
||||
pdnpToSrefTransition = state->getLastCommand(Command::PDNPX,bank).getStart() >= time;
|
||||
if (config.PowerDownMode == EPowerDownMode::Staggered) {
|
||||
pdnpToSrefTransition = state->getLastCommand(Command::PDNPX,
|
||||
bank).getStart() >= time;
|
||||
}
|
||||
if (pdnpToSrefTransition)
|
||||
{
|
||||
powerDownManager->sleep(bank,time);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pdnpToSrefTransition) {
|
||||
powerDownManager->sleep(bank, time);
|
||||
} else {
|
||||
refreshManager->scheduleRefresh(payload, time);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ControllerCore::scheduleRequest(Command command, 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);
|
||||
@@ -164,9 +157,8 @@ void ControllerCore::scheduleRequest(Command command, tlm::tlm_generic_payload &
|
||||
state->change(scheduledCommand);
|
||||
controller.send(scheduledCommand, payload);
|
||||
} else {
|
||||
if(!((command == Command::Precharge || command == Command::Activate)
|
||||
&& refreshManager->hasCollision(scheduledCommand)))
|
||||
{
|
||||
if (!((command == Command::Precharge || command == Command::Activate)
|
||||
&& refreshManager->hasCollision(scheduledCommand))) {
|
||||
state->change(scheduledCommand);
|
||||
controller.send(scheduledCommand, payload);
|
||||
}
|
||||
@@ -174,20 +166,21 @@ void ControllerCore::scheduleRequest(Command command, tlm::tlm_generic_payload &
|
||||
}
|
||||
|
||||
ScheduledCommand ControllerCore::schedule(Command command, sc_time start,
|
||||
tlm::tlm_generic_payload& payload)
|
||||
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;
|
||||
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::hasPendingRequests()
|
||||
{
|
||||
for (Bank bank : getBanks())
|
||||
{
|
||||
for (Bank bank : getBanks()) {
|
||||
if (numberOfPayloads[bank] != 0)
|
||||
return true;
|
||||
}
|
||||
@@ -202,40 +195,33 @@ bool ControllerCore::bankIsBusy(Bank bank)
|
||||
|
||||
if (lastScheduledCommand.isNoCommand())
|
||||
return false;
|
||||
else if (lastScheduledCommand.commandIsIn( { Command::Write, Command::Read }))
|
||||
{
|
||||
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, Command::Precharge, Command::PrechargeAll, Command::Activate }))
|
||||
{
|
||||
else if (lastScheduledCommand.commandIsIn( { Command::WriteA, Command::ReadA, Command::Precharge, Command::PrechargeAll, Command::Activate })) {
|
||||
return (time < lastScheduledCommand.getEnd());
|
||||
}
|
||||
else if (lastScheduledCommand.getCommand() == Command::AutoRefresh)
|
||||
{
|
||||
else if (lastScheduledCommand.getCommand() == Command::AutoRefresh) {
|
||||
return (time < lastScheduledCommand.getEnd());
|
||||
}
|
||||
else if (lastScheduledCommand.commandIsIn( { Command::SREFX, Command::PDNPX, Command::PDNAX, Command::SREF, Command::PDNP,
|
||||
Command::PDNA }))
|
||||
{
|
||||
} else if (lastScheduledCommand.commandIsIn( { Command::SREFX, Command::PDNPX, Command::PDNAX, Command::SREF, Command::PDNP,
|
||||
Command::PDNA
|
||||
})) {
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
SC_REPORT_FATAL("Core", "Last command unkown");
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const std::vector<Bank>& ControllerCore::getBanks()
|
||||
const std::vector<Bank> &ControllerCore::getBanks()
|
||||
{
|
||||
static std::vector<Bank> banks;
|
||||
|
||||
if (banks.size() == 0)
|
||||
{
|
||||
for (unsigned int i = 0; i < config.memSpec.NumberOfBanks; i++)
|
||||
{
|
||||
if (banks.size() == 0) {
|
||||
for (unsigned int i = 0; i < config.memSpec.NumberOfBanks; i++) {
|
||||
banks.push_back(Bank(i));
|
||||
}
|
||||
}
|
||||
@@ -246,15 +232,14 @@ const std::vector<Bank>& ControllerCore::getBanks()
|
||||
std::vector<Bank> ControllerCore::getFreeBanks()
|
||||
{
|
||||
std::vector<Bank> freeBanks;
|
||||
for(Bank bank: getBanks())
|
||||
{
|
||||
if(!bankIsBusy(bank))
|
||||
for (Bank bank : getBanks()) {
|
||||
if (!bankIsBusy(bank))
|
||||
freeBanks.push_back(bank);
|
||||
}
|
||||
return freeBanks;
|
||||
}
|
||||
|
||||
ICommandChecker& ControllerCore::getCommandChecker(Command command)
|
||||
ICommandChecker &ControllerCore::getCommandChecker(Command command)
|
||||
{
|
||||
return *getElementFromMap(commandChecker, command);
|
||||
}
|
||||
|
||||
@@ -54,31 +54,36 @@ using namespace std;
|
||||
class ControllerCore : public sc_module
|
||||
{
|
||||
public:
|
||||
ControllerCore(sc_module_name /*name*/, IController& controller, std::map<Bank, int>& numberOfPayloads);
|
||||
ControllerCore(sc_module_name /*name*/, IController &controller,
|
||||
std::map<Bank, int> &numberOfPayloads);
|
||||
virtual ~ControllerCore();
|
||||
|
||||
void scheduleRequest(Command command, tlm::tlm_generic_payload& payload);
|
||||
void triggerRefresh(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();
|
||||
const std::vector<Bank> &getBanks();
|
||||
std::vector<Bank> getFreeBanks();
|
||||
const RowBufferState& getRowBufferStates(){return *(state->rowBufferStates);}
|
||||
const RowBufferState &getRowBufferStates()
|
||||
{
|
||||
return *(state->rowBufferStates);
|
||||
}
|
||||
bool hasPendingRequests();
|
||||
bool bankIsBusy(Bank bank);
|
||||
|
||||
ICommandChecker& getCommandChecker(Command command);
|
||||
ICommandChecker &getCommandChecker(Command command);
|
||||
|
||||
Configuration config;
|
||||
ControllerState *state;
|
||||
IController& controller;
|
||||
IPowerDownManager* powerDownManager;
|
||||
IRefreshManager* refreshManager;
|
||||
std::map<Bank,int>& numberOfPayloads;
|
||||
IController &controller;
|
||||
IPowerDownManager *powerDownManager;
|
||||
IRefreshManager *refreshManager;
|
||||
std::map<Bank, int> &numberOfPayloads;
|
||||
|
||||
private:
|
||||
|
||||
ScheduledCommand schedule(Command command, sc_time start, tlm::tlm_generic_payload &payload);
|
||||
std::map<Command, ICommandChecker*> commandChecker;
|
||||
ScheduledCommand schedule(Command command, sc_time start,
|
||||
tlm::tlm_generic_payload &payload);
|
||||
std::map<Command, ICommandChecker *> commandChecker;
|
||||
void printDebugMessage(string message);
|
||||
};
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
|
||||
Slots::Slots(sc_time clk) :
|
||||
clk(clk)
|
||||
clk(clk)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -48,41 +48,40 @@ Slots::~Slots()
|
||||
{
|
||||
}
|
||||
|
||||
void Slots::moveCommandToNextFreeSlot(ScheduledCommand& command)
|
||||
void Slots::moveCommandToNextFreeSlot(ScheduledCommand &command)
|
||||
{
|
||||
while(!isFree(command.getStart()))
|
||||
command.delayStart(clk);
|
||||
while (!isFree(command.getStart()))
|
||||
command.delayStart(clk);
|
||||
}
|
||||
|
||||
void Slots::cleanUpSlots(sc_time time)
|
||||
{
|
||||
slotSet.erase(slotSet.begin(), slotSet.lower_bound(time));
|
||||
slotSet.erase(slotSet.begin(), slotSet.lower_bound(time));
|
||||
}
|
||||
|
||||
void Slots::blockSlot(sc_time time)
|
||||
{
|
||||
sc_assert(isClkAligned(time, clk));
|
||||
slotSet.insert(time);
|
||||
sc_assert(isClkAligned(time, clk));
|
||||
slotSet.insert(time);
|
||||
}
|
||||
|
||||
bool Slots::isFree(sc_time time)
|
||||
{
|
||||
return (slotSet.count(time) == 0);
|
||||
return (slotSet.count(time) == 0);
|
||||
}
|
||||
|
||||
void Slots::blockSlots(sc_time begin, sc_time end, bool excludeBorders)
|
||||
{
|
||||
sc_assert(isClkAligned(begin, clk));
|
||||
sc_assert(isClkAligned(end, clk));
|
||||
sc_assert(isClkAligned(begin, clk));
|
||||
sc_assert(isClkAligned(end, clk));
|
||||
|
||||
if (excludeBorders)
|
||||
{
|
||||
begin += clk;
|
||||
end -= clk;
|
||||
}
|
||||
if (excludeBorders) {
|
||||
begin += clk;
|
||||
end -= clk;
|
||||
}
|
||||
|
||||
for (sc_time time = begin; time <= end; time += clk) {
|
||||
blockSlot(time);
|
||||
}
|
||||
for (sc_time time = begin; time <= end; time += clk) {
|
||||
blockSlot(time);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ public:
|
||||
Slots(sc_time clk);
|
||||
virtual ~Slots();
|
||||
|
||||
void moveCommandToNextFreeSlot(ScheduledCommand& command);
|
||||
void moveCommandToNextFreeSlot(ScheduledCommand &command);
|
||||
void cleanUpSlots(sc_time time);
|
||||
void blockSlot(sc_time time);
|
||||
bool isFree(sc_time);
|
||||
|
||||
@@ -43,7 +43,8 @@
|
||||
|
||||
|
||||
|
||||
sc_time getDelayToMeetConstraint(sc_time previous, sc_time start, sc_time constraint)
|
||||
sc_time getDelayToMeetConstraint(sc_time previous, sc_time start,
|
||||
sc_time constraint)
|
||||
{
|
||||
if (previous + constraint > start)
|
||||
return previous + constraint - start;
|
||||
@@ -66,49 +67,33 @@ const sc_time clkAlign(sc_time time, Alignment alignment)
|
||||
}
|
||||
|
||||
// Returns the execution time for commands that have a fixed execution time
|
||||
sc_time getExecutionTime(Command command, tlm::tlm_generic_payload& payload)
|
||||
sc_time getExecutionTime(Command command, tlm::tlm_generic_payload &payload)
|
||||
{
|
||||
MemSpec& config = Configuration::getInstance().memSpec;
|
||||
MemSpec &config = Configuration::getInstance().memSpec;
|
||||
|
||||
if (command == Command::Precharge || command == Command::PrechargeAll)
|
||||
{
|
||||
if (command == Command::Precharge || command == Command::PrechargeAll) {
|
||||
return config.tRP;
|
||||
}
|
||||
else if (command == Command::Activate)
|
||||
{
|
||||
} else if (command == Command::Activate) {
|
||||
return config.tRCD;
|
||||
}
|
||||
else if (command == Command::Read)
|
||||
{
|
||||
} else if (command == Command::Read) {
|
||||
return config.tRL + getReadAccessTime();
|
||||
}
|
||||
else if (command == Command::ReadA)
|
||||
{
|
||||
} else if (command == Command::ReadA) {
|
||||
return config.tRTP + config.tRP;
|
||||
}
|
||||
else if (command == Command::Write)
|
||||
{
|
||||
} else if (command == Command::Write) {
|
||||
return config.tWL + getWriteAccessTime();
|
||||
}
|
||||
else if (command == Command::WriteA)
|
||||
{
|
||||
} else if (command == Command::WriteA) {
|
||||
return config.tWL + getWriteAccessTime() + config.tWR + config.tRP;
|
||||
}
|
||||
else if (command == Command::PrechargeAll)
|
||||
{
|
||||
} else if (command == Command::PrechargeAll) {
|
||||
return config.tRP;
|
||||
}
|
||||
else if (command == Command::AutoRefresh)
|
||||
{
|
||||
return getElementFromMap(config.refreshTimings, DramExtension::getExtension(payload).getBank()).tRFC;
|
||||
}
|
||||
else if (command == Command::PDNAX || command == Command::PDNPX || command == Command::SREFX)
|
||||
{
|
||||
} else if (command == Command::AutoRefresh) {
|
||||
return getElementFromMap(config.refreshTimings,
|
||||
DramExtension::getExtension(payload).getBank()).tRFC;
|
||||
} else if (command == Command::PDNAX || command == Command::PDNPX
|
||||
|| command == Command::SREFX) {
|
||||
return config.clk;
|
||||
}
|
||||
else
|
||||
{
|
||||
SC_REPORT_FATAL("getExecutionTime", "command not known or command doesn't have a fixed execution time");
|
||||
} else {
|
||||
SC_REPORT_FATAL("getExecutionTime",
|
||||
"command not known or command doesn't have a fixed execution time");
|
||||
return SC_ZERO_TIME;
|
||||
}
|
||||
}
|
||||
@@ -116,18 +101,14 @@ sc_time getExecutionTime(Command command, tlm::tlm_generic_payload& payload)
|
||||
// Returns the minimum execution time for commands that have a variable execution time
|
||||
sc_time getMinExecutionTimeForPowerDownCmd(Command command)
|
||||
{
|
||||
MemSpec& config = Configuration::getInstance().memSpec;
|
||||
if (command == Command::PDNA || command == Command::PDNP)
|
||||
{
|
||||
MemSpec &config = Configuration::getInstance().memSpec;
|
||||
if (command == Command::PDNA || command == Command::PDNP) {
|
||||
return config.tCKE;
|
||||
}
|
||||
else if (command == Command::SREF)
|
||||
{
|
||||
} else if (command == Command::SREF) {
|
||||
return config.tCKESR;
|
||||
}
|
||||
else
|
||||
{
|
||||
SC_REPORT_FATAL("getMinimalExecutionTime", "command is not know or command has a fixed execution time");
|
||||
} else {
|
||||
SC_REPORT_FATAL("getMinimalExecutionTime",
|
||||
"command is not know or command has a fixed execution time");
|
||||
return SC_ZERO_TIME;
|
||||
}
|
||||
}
|
||||
@@ -140,21 +121,20 @@ bool isClkAligned(sc_time time, sc_time clk)
|
||||
|
||||
sc_time getReadAccessTime()
|
||||
{
|
||||
Configuration& config = Configuration::getInstance();
|
||||
return (config.memSpec.BurstLength / config.memSpec.DataRate)*config.memSpec.clk;
|
||||
Configuration &config = Configuration::getInstance();
|
||||
return (config.memSpec.BurstLength / config.memSpec.DataRate) *
|
||||
config.memSpec.clk;
|
||||
}
|
||||
|
||||
sc_time getWriteAccessTime()
|
||||
{
|
||||
Configuration& config = Configuration::getInstance();
|
||||
Configuration &config = Configuration::getInstance();
|
||||
|
||||
if (config.memSpec.DataRate == 1)
|
||||
{
|
||||
if (config.memSpec.DataRate == 1) {
|
||||
return config.memSpec.clk * (config.memSpec.BurstLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
return config.memSpec.clk * (config.memSpec.BurstLength / config.memSpec.DataRate);
|
||||
} else {
|
||||
return config.memSpec.clk * (config.memSpec.BurstLength /
|
||||
config.memSpec.DataRate);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,11 +44,12 @@
|
||||
|
||||
|
||||
sc_time getMinExecutionTimeForPowerDownCmd(Command command);
|
||||
sc_time getExecutionTime(Command command, tlm::tlm_generic_payload& payload);
|
||||
sc_time getExecutionTime(Command command, tlm::tlm_generic_payload &payload);
|
||||
|
||||
sc_time getReadAccessTime();
|
||||
sc_time getWriteAccessTime();
|
||||
sc_time getDelayToMeetConstraint(sc_time previous, sc_time start, sc_time constraint);
|
||||
sc_time getDelayToMeetConstraint(sc_time previous, sc_time start,
|
||||
sc_time constraint);
|
||||
|
||||
enum Alignment {UP, DOWN};
|
||||
const sc_time clkAlign(sc_time time, Alignment alignment = UP);
|
||||
|
||||
@@ -53,16 +53,11 @@ Configuration::Configuration()
|
||||
|
||||
bool string2bool(string s)
|
||||
{
|
||||
if(s.compare("0") == 0)
|
||||
{
|
||||
if (s.compare("0") == 0) {
|
||||
return false;
|
||||
}
|
||||
else if(s.compare("1") == 0)
|
||||
{
|
||||
} else if (s.compare("1") == 0) {
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
SC_REPORT_FATAL("Configuration", ("Could not convert to bool: " + s).c_str());
|
||||
return false;
|
||||
}
|
||||
@@ -80,14 +75,13 @@ unsigned long long string2ull(string s)
|
||||
|
||||
StorageMode string2StoreMode(string s)
|
||||
{
|
||||
if(s == "NoStorage")
|
||||
if (s == "NoStorage")
|
||||
return StorageMode::NoStorage;
|
||||
else if(s == "Store")
|
||||
else if (s == "Store")
|
||||
return StorageMode::Store;
|
||||
else if (s == "ErrorModel")
|
||||
return StorageMode::ErrorModel;
|
||||
else
|
||||
{
|
||||
else {
|
||||
SC_REPORT_FATAL("Configuration", ("Unknown StorageMode: " + s).c_str());
|
||||
throw;
|
||||
}
|
||||
@@ -95,16 +89,15 @@ StorageMode string2StoreMode(string s)
|
||||
|
||||
EPowerDownMode string2PDNMode(string s)
|
||||
{
|
||||
if(s == "NoPowerDown")
|
||||
if (s == "NoPowerDown")
|
||||
return EPowerDownMode::NoPowerDown;
|
||||
else if(s == "Staggered")
|
||||
else if (s == "Staggered")
|
||||
return EPowerDownMode::Staggered;
|
||||
else if (s == "TimeoutPDN")
|
||||
return EPowerDownMode::TimeoutPDN;
|
||||
else if (s == "TimeoutSREF")
|
||||
return EPowerDownMode::TimeoutSREF;
|
||||
else
|
||||
{
|
||||
else {
|
||||
SC_REPORT_FATAL("Configuration", ("Unknown PowerDownMode: " + s).c_str());
|
||||
throw;
|
||||
}
|
||||
@@ -112,15 +105,14 @@ EPowerDownMode string2PDNMode(string s)
|
||||
|
||||
ECCControllerMode string2ECCControllerMode(string s)
|
||||
{
|
||||
if(s == "Disabled")
|
||||
return ECCControllerMode::Disabled;
|
||||
else if(s == "Hamming")
|
||||
return ECCControllerMode::Hamming;
|
||||
else
|
||||
{
|
||||
SC_REPORT_FATAL("Configuration", ("Unknown ECCControllerMode: " + s).c_str());
|
||||
throw;
|
||||
}
|
||||
if (s == "Disabled")
|
||||
return ECCControllerMode::Disabled;
|
||||
else if (s == "Hamming")
|
||||
return ECCControllerMode::Hamming;
|
||||
else {
|
||||
SC_REPORT_FATAL("Configuration", ("Unknown ECCControllerMode: " + s).c_str());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
enum sc_time_unit string2TimeUnit(string s)
|
||||
@@ -138,131 +130,133 @@ enum sc_time_unit string2TimeUnit(string s)
|
||||
else if (s == "fs")
|
||||
return SC_FS;
|
||||
else {
|
||||
SC_REPORT_FATAL("Configuration", ("Could not convert to enum sc_time_unit: " + s).c_str());
|
||||
SC_REPORT_FATAL("Configuration",
|
||||
("Could not convert to enum sc_time_unit: " + s).c_str());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void Configuration::setParameter(std::string name, std::string value)
|
||||
{
|
||||
if(name == "BankwiseLogic")
|
||||
if (name == "BankwiseLogic")
|
||||
BankwiseLogic = string2bool(value);
|
||||
else if(name == "OpenPagePolicy")
|
||||
else if (name == "OpenPagePolicy")
|
||||
OpenPagePolicy = string2bool(value);
|
||||
else if(name == "MaxNrOfTransactions")
|
||||
else if (name == "MaxNrOfTransactions")
|
||||
MaxNrOfTransactions = string2int(value);
|
||||
else if(name == "Scheduler")
|
||||
else if (name == "Scheduler")
|
||||
Scheduler = value;
|
||||
else if(name == "SJFProbability")
|
||||
if (string2int(value) > 100 || string2int(value) < 0) {
|
||||
SC_REPORT_FATAL("Configuration", ("Invalid value for parameter " + name + ". This parameter must be between 0 and 100.").c_str());
|
||||
} else {
|
||||
SJFProbability = string2int(value);
|
||||
}
|
||||
else if (name == "SJFProbability")
|
||||
if (string2int(value) > 100 || string2int(value) < 0) {
|
||||
SC_REPORT_FATAL("Configuration",
|
||||
("Invalid value for parameter " + name +
|
||||
". This parameter must be between 0 and 100.").c_str());
|
||||
} else {
|
||||
SJFProbability = string2int(value);
|
||||
}
|
||||
else if (name == "RequestBufferSize")
|
||||
RequestBufferSize = string2int(value);
|
||||
else if(name == "Capsize")
|
||||
RequestBufferSize = string2int(value);
|
||||
else if (name == "Capsize")
|
||||
Capsize = string2int(value);
|
||||
else if(name == "PowerDownTimeout")
|
||||
else if (name == "PowerDownTimeout")
|
||||
powerDownTimeoutInClk = string2int(value);
|
||||
else if(name == "PowerDownMode")
|
||||
else if (name == "PowerDownMode")
|
||||
PowerDownMode = string2PDNMode(value);
|
||||
else if(name == "ReadWriteGrouping")
|
||||
else if (name == "ReadWriteGrouping")
|
||||
ReadWriteGrouping = string2bool(value);
|
||||
else if(name == "ReorderBuffer")
|
||||
else if (name == "ReorderBuffer")
|
||||
ReorderBuffer = string2bool(value);
|
||||
|
||||
//SimConfig------------------------------------------------
|
||||
else if(name == "SimulationName")
|
||||
else if (name == "SimulationName")
|
||||
SimulationName = value;
|
||||
else if(name == "DatabaseRecording")
|
||||
else if (name == "DatabaseRecording")
|
||||
DatabaseRecording = string2bool(value);
|
||||
else if(name == "PowerAnalysis")
|
||||
else if (name == "PowerAnalysis")
|
||||
PowerAnalysis = string2bool(value);
|
||||
else if (name == "EnableWindowing")
|
||||
EnableWindowing = string2bool(value);
|
||||
else if(name == "WindowSize")
|
||||
if(string2int(value) < 1) {
|
||||
SC_REPORT_FATAL("Configuration", ("Invalid value for parameter " + name + ". This parameter must be at least one.").c_str());
|
||||
}
|
||||
else
|
||||
else if (name == "WindowSize")
|
||||
if (string2int(value) < 1) {
|
||||
SC_REPORT_FATAL("Configuration",
|
||||
("Invalid value for parameter " + name +
|
||||
". This parameter must be at least one.").c_str());
|
||||
} else
|
||||
WindowSize = string2int(value);
|
||||
else if(name == "Debug")
|
||||
else if (name == "Debug")
|
||||
Debug = string2bool(value);
|
||||
else if (name == "NumberOfMemChannels") {
|
||||
NumberOfMemChannels = string2int(value);
|
||||
unsigned int maxNumberofMemChannels = xmlAddressDecoder::getInstance().amount["channel"];
|
||||
if (NumberOfMemChannels > maxNumberofMemChannels) {
|
||||
unsigned int maxNumberofMemChannels =
|
||||
AddressDecoder::getInstance().amount["channel"];
|
||||
if (NumberOfMemChannels > maxNumberofMemChannels) {
|
||||
SC_REPORT_FATAL("Configuration", ("Invalid value for parameter "
|
||||
+ name
|
||||
+ ". Value is out of range. The maximum value according to "
|
||||
+ "the address mapping configuration file is "
|
||||
+ std::to_string(maxNumberofMemChannels) + ".").c_str());
|
||||
}
|
||||
}
|
||||
else if (name == "ControllerCoreDisableRefresh")
|
||||
}
|
||||
} else if (name == "ControllerCoreDisableRefresh")
|
||||
ControllerCoreDisableRefresh = string2bool(value);
|
||||
else if (name == "ControllerCoreForceMaxRefBurst")
|
||||
ControllerCoreForceMaxRefBurst = string2bool(value);
|
||||
else if (name == "ControllerCoreEnableRefPostpone")
|
||||
{
|
||||
else if (name == "ControllerCoreEnableRefPostpone") {
|
||||
ControllerCoreEnableRefPostpone = string2bool(value);
|
||||
// Refresh postpone feature available for DDR3 only in the current
|
||||
// version of DRAMsys.
|
||||
if (ControllerCoreEnableRefPostpone && memSpec.MemoryType != "DDR3") {
|
||||
SC_REPORT_FATAL("Configuration", (name + " requires memory type DDR3.").c_str());
|
||||
SC_REPORT_FATAL("Configuration",
|
||||
(name + " requires memory type DDR3.").c_str());
|
||||
}
|
||||
}
|
||||
else if (name == "ControllerCoreEnableRefPullIn")
|
||||
{
|
||||
} else if (name == "ControllerCoreEnableRefPullIn") {
|
||||
ControllerCoreEnableRefPullIn = string2bool(value);
|
||||
// Refresh pull-in feature available for DDR3 only in the current
|
||||
// version of DRAMsys.
|
||||
if (ControllerCoreEnableRefPullIn && memSpec.MemoryType != "DDR3") {
|
||||
SC_REPORT_FATAL("Configuration", (name + " requires memory type DDR3.").c_str());
|
||||
SC_REPORT_FATAL("Configuration",
|
||||
(name + " requires memory type DDR3.").c_str());
|
||||
}
|
||||
}
|
||||
else if (name == "ControllerCoreMaxPostponedARCmd")
|
||||
} else if (name == "ControllerCoreMaxPostponedARCmd")
|
||||
ControllerCoreMaxPostponedARCmd = string2int(value);
|
||||
else if (name == "ControllerCoreMaxPulledInARCmd")
|
||||
ControllerCoreMaxPulledInARCmd = string2int(value);
|
||||
else if (name == "ThermalSimulation")
|
||||
ThermalSimulation = string2bool(value);
|
||||
else if(name == "SimulationProgressBar")
|
||||
else if (name == "SimulationProgressBar")
|
||||
SimulationProgressBar = string2bool(value);
|
||||
else if(name == "NumberOfDevicesOnDIMM")
|
||||
if (string2int(value) < 1) {
|
||||
SC_REPORT_FATAL("Configuration", ("Invalid value for parameter " + name + ". This parameter must be at least one.").c_str());
|
||||
} else
|
||||
NumberOfDevicesOnDIMM = string2int(value);
|
||||
else if(name == "AddressOffset")
|
||||
{
|
||||
else if (name == "NumberOfDevicesOnDIMM")
|
||||
if (string2int(value) < 1) {
|
||||
SC_REPORT_FATAL("Configuration",
|
||||
("Invalid value for parameter " + name +
|
||||
". This parameter must be at least one.").c_str());
|
||||
} else
|
||||
NumberOfDevicesOnDIMM = string2int(value);
|
||||
else if (name == "AddressOffset") {
|
||||
#ifdef DRAMSYS_GEM5
|
||||
AddressOffset = string2ull(value);
|
||||
#else
|
||||
AddressOffset = 0;
|
||||
#endif
|
||||
cout << "Address Offset: " << AddressOffset << endl;
|
||||
}
|
||||
else if(name == "CheckTLM2Protocol")
|
||||
} else if (name == "CheckTLM2Protocol")
|
||||
CheckTLM2Protocol = string2bool(value);
|
||||
else if(name == "ECCControllerMode")
|
||||
ECCMode = string2ECCControllerMode(value);
|
||||
else if (name == "ECCControllerMode")
|
||||
ECCMode = string2ECCControllerMode(value);
|
||||
// Specification for ErrorChipSeed, ErrorCSVFile path and StoreMode
|
||||
else if(name == "ErrorChipSeed")
|
||||
else if (name == "ErrorChipSeed")
|
||||
ErrorChipSeed = string2int(value);
|
||||
else if(name == "ErrorCSVFile")
|
||||
else if (name == "ErrorCSVFile")
|
||||
ErrorCSVFile = value;
|
||||
else if(name == "StoreMode")
|
||||
else if (name == "StoreMode")
|
||||
StoreMode = string2StoreMode(value);
|
||||
// Temperature Simulation related
|
||||
else if (name == "TemperatureScale") {
|
||||
if (value != "Celsius" && value != "Fahrenheit" && value != "Kelvin") {
|
||||
SC_REPORT_FATAL("Configuration", ("Invalid value for parameter " + name + ".").c_str());
|
||||
SC_REPORT_FATAL("Configuration",
|
||||
("Invalid value for parameter " + name + ".").c_str());
|
||||
}
|
||||
temperatureSim.TemperatureScale = value;
|
||||
}
|
||||
else if (name == "StaticTemperatureDefaultValue")
|
||||
} else if (name == "StaticTemperatureDefaultValue")
|
||||
temperatureSim.StaticTemperatureDefaultValue = string2int(value);
|
||||
else if (name == "ThermalSimPeriod")
|
||||
temperatureSim.ThermalSimPeriod = std::stod(value.c_str());
|
||||
@@ -271,8 +265,7 @@ void Configuration::setParameter(std::string name, std::string value)
|
||||
else if (name == "PowerInfoFile") {
|
||||
temperatureSim.powerInfoFile = value;
|
||||
temperatureSim.parsePowerInfoFile();
|
||||
}
|
||||
else if (name == "IceServerIp")
|
||||
} else if (name == "IceServerIp")
|
||||
temperatureSim.IceServerIp = value;
|
||||
else if (name == "IceServerPort")
|
||||
temperatureSim.IceServerPort = string2int(value);
|
||||
@@ -284,9 +277,9 @@ void Configuration::setParameter(std::string name, std::string value)
|
||||
temperatureSim.GenerateTemperatureMap = string2bool(value);
|
||||
else if (name == "GeneratePowerMap")
|
||||
temperatureSim.GeneratePowerMap = string2bool(value);
|
||||
else
|
||||
{
|
||||
SC_REPORT_FATAL("Configuration", ("Parameter " + name + " not defined in Configuration").c_str());
|
||||
else {
|
||||
SC_REPORT_FATAL("Configuration",
|
||||
("Parameter " + name + " not defined in Configuration").c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,10 +294,10 @@ std::string Configuration::getPathToResources()
|
||||
return pathToResources;
|
||||
}
|
||||
|
||||
void Configuration::setParameters(std::map<std::string, std::string> parameterMap)
|
||||
void Configuration::setParameters(std::map<std::string, std::string>
|
||||
parameterMap)
|
||||
{
|
||||
for(auto item : parameterMap)
|
||||
{
|
||||
for (auto item : parameterMap) {
|
||||
setParameter(item.first, item.second);
|
||||
}
|
||||
}
|
||||
@@ -349,7 +342,8 @@ unsigned int Configuration::getBytesPerBurst()
|
||||
// The least significant bits of the physical address are the byte
|
||||
// offset of the N-byte-wide memory module (DIMM) (a single data word
|
||||
// or burst element has N bytes. N = 2^(# bits for byte offset)).
|
||||
unsigned int burstElementSizeInBytes = xmlAddressDecoder::getInstance().amount["bytes"];
|
||||
unsigned int burstElementSizeInBytes =
|
||||
AddressDecoder::getInstance().amount["bytes"];
|
||||
assert(bytesPerBurst == (burstElementSizeInBytes * memSpec.BurstLength));
|
||||
}
|
||||
|
||||
@@ -359,12 +353,11 @@ unsigned int Configuration::getBytesPerBurst()
|
||||
// Changes the number of bytes depeding on the ECC Controller. This function is needed for modules which get data directly or indirectly from the ECC Controller
|
||||
unsigned int Configuration::adjustNumBytesAfterECC(unsigned nBytes)
|
||||
{
|
||||
// Manipulate the number of bytes only if there is an ECC Controller selected
|
||||
if(ECCMode == ECCControllerMode::Disabled)
|
||||
return nBytes;
|
||||
else
|
||||
{
|
||||
assert(pECC != nullptr);
|
||||
return pECC->AllocationSize(nBytes);
|
||||
}
|
||||
// Manipulate the number of bytes only if there is an ECC Controller selected
|
||||
if (ECCMode == ECCControllerMode::Disabled)
|
||||
return nBytes;
|
||||
else {
|
||||
assert(pECC != nullptr);
|
||||
return pECC->AllocationSize(nBytes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,14 +47,13 @@
|
||||
|
||||
#include "../../../error/eccbaseclass.h"
|
||||
|
||||
enum class StorageMode{NoStorage, Store, ErrorModel};
|
||||
enum class StorageMode {NoStorage, Store, ErrorModel};
|
||||
|
||||
enum class EPowerDownMode{NoPowerDown, Staggered, TimeoutPDN, TimeoutSREF};
|
||||
enum class EPowerDownMode {NoPowerDown, Staggered, TimeoutPDN, TimeoutSREF};
|
||||
|
||||
enum class ECCControllerMode{Disabled, Hamming};
|
||||
enum class ECCControllerMode {Disabled, Hamming};
|
||||
|
||||
struct Configuration
|
||||
{
|
||||
struct Configuration {
|
||||
static std::string memspecUri;
|
||||
static std::string mcconfigUri;
|
||||
std::string pathToResources;
|
||||
@@ -69,7 +68,10 @@ struct Configuration
|
||||
unsigned int SJFProbability;
|
||||
unsigned int RequestBufferSize;
|
||||
unsigned int Capsize = 5;
|
||||
sc_time getPowerDownTimeout(){return powerDownTimeoutInClk*memSpec.clk;}
|
||||
sc_time getPowerDownTimeout()
|
||||
{
|
||||
return powerDownTimeoutInClk * memSpec.clk;
|
||||
}
|
||||
EPowerDownMode PowerDownMode = EPowerDownMode::Staggered;
|
||||
bool ReadWriteGrouping = false;
|
||||
bool ReorderBuffer = false;
|
||||
@@ -92,8 +94,8 @@ struct Configuration
|
||||
bool SimulationProgressBar = false;
|
||||
unsigned int NumberOfDevicesOnDIMM = 1;
|
||||
bool CheckTLM2Protocol = false;
|
||||
ECCControllerMode ECCMode = ECCControllerMode::Disabled;
|
||||
ECCBaseClass* pECC = nullptr;
|
||||
ECCControllerMode ECCMode = ECCControllerMode::Disabled;
|
||||
ECCBaseClass *pECC = nullptr;
|
||||
bool gem5 = false;
|
||||
unsigned long long int AddressOffset = 0;
|
||||
|
||||
@@ -105,7 +107,7 @@ struct Configuration
|
||||
|
||||
//Configs for Seed, csv file and StorageMode
|
||||
unsigned int ErrorChipSeed;
|
||||
std::string ErrorCSVFile ="not defined.";
|
||||
std::string ErrorCSVFile = "not defined.";
|
||||
StorageMode StoreMode;
|
||||
|
||||
// Temperature Simulation related
|
||||
@@ -114,7 +116,7 @@ struct Configuration
|
||||
std::uint64_t getSimMemSizeInBytes();
|
||||
unsigned int getDataBusWidth();
|
||||
unsigned int getBytesPerBurst();
|
||||
unsigned int adjustNumBytesAfterECC(unsigned bytes);
|
||||
unsigned int adjustNumBytesAfterECC(unsigned bytes);
|
||||
void setPathToResources(std::string path);
|
||||
std::string getPathToResources();
|
||||
|
||||
|
||||
@@ -41,19 +41,20 @@
|
||||
using namespace tinyxml2;
|
||||
using namespace std;
|
||||
|
||||
void ConfigurationLoader::loadSimConfig(Configuration& config, string simconfigUri)
|
||||
void ConfigurationLoader::loadSimConfig(Configuration &config,
|
||||
string simconfigUri)
|
||||
{
|
||||
tinyxml2::XMLDocument doc;
|
||||
|
||||
loadXML(simconfigUri, doc);
|
||||
XMLElement* simconfig = doc.FirstChildElement("simconfig");
|
||||
XMLElement *simconfig = doc.FirstChildElement("simconfig");
|
||||
loadConfig(config, simconfig);
|
||||
}
|
||||
|
||||
void ConfigurationLoader::loadSimConfig(Configuration& config, XMLElement* simconfig)
|
||||
void ConfigurationLoader::loadSimConfig(Configuration &config,
|
||||
XMLElement *simconfig)
|
||||
{
|
||||
if(simconfig->Attribute("src"))
|
||||
{
|
||||
if (simconfig->Attribute("src")) {
|
||||
XMLDocument doc;
|
||||
string src(simconfig->Attribute("src"));
|
||||
loadXML(src, doc);
|
||||
@@ -62,12 +63,14 @@ void ConfigurationLoader::loadSimConfig(Configuration& config, XMLElement* simco
|
||||
loadConfig(config, simconfig);
|
||||
}
|
||||
|
||||
void ConfigurationLoader::loadTemperatureSimConfig(Configuration &config, std::string thermalsimconfigUri)
|
||||
void ConfigurationLoader::loadTemperatureSimConfig(Configuration &config,
|
||||
std::string thermalsimconfigUri)
|
||||
{
|
||||
loadConfigFromUri(config, thermalsimconfigUri, "thermalsimconfig");
|
||||
}
|
||||
|
||||
void ConfigurationLoader::loadTemperatureSimConfig(Configuration &config, XMLElement *thermalsimconfig)
|
||||
void ConfigurationLoader::loadTemperatureSimConfig(Configuration &config,
|
||||
XMLElement *thermalsimconfig)
|
||||
{
|
||||
if (thermalsimconfig->Attribute("src")) {
|
||||
// Configuration is inside another a file
|
||||
@@ -78,18 +81,19 @@ void ConfigurationLoader::loadTemperatureSimConfig(Configuration &config, XMLEle
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigurationLoader::loadConfig(Configuration& config, XMLElement* configNode)
|
||||
void ConfigurationLoader::loadConfig(Configuration &config,
|
||||
XMLElement *configNode)
|
||||
{
|
||||
XMLElement* element;
|
||||
XMLElement *element;
|
||||
for (element = configNode->FirstChildElement(); element != NULL;
|
||||
element = element->NextSiblingElement())
|
||||
{
|
||||
element = element->NextSiblingElement()) {
|
||||
config.setParameter(element->Name(), element->Attribute("value"));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigurationLoader::loadConfigFromUri(Configuration &config, std::string uri, std::string first_element)
|
||||
void ConfigurationLoader::loadConfigFromUri(Configuration &config,
|
||||
std::string uri, std::string first_element)
|
||||
{
|
||||
tinyxml2::XMLDocument doc;
|
||||
loadXML(uri, doc);
|
||||
@@ -97,75 +101,66 @@ void ConfigurationLoader::loadConfigFromUri(Configuration &config, std::string u
|
||||
loadConfig(config, e);
|
||||
}
|
||||
|
||||
void ConfigurationLoader::loadMemSpec(Configuration& config, string memspecUri)
|
||||
void ConfigurationLoader::loadMemSpec(Configuration &config, string memspecUri)
|
||||
{
|
||||
tinyxml2::XMLDocument doc;
|
||||
config.memspecUri = memspecUri;
|
||||
loadXML(memspecUri, doc);
|
||||
XMLElement* memspec = doc.FirstChildElement("memspec");
|
||||
XMLElement *memspec = doc.FirstChildElement("memspec");
|
||||
loadMemSpec(config, memspec);
|
||||
}
|
||||
|
||||
void ConfigurationLoader::loadMemSpec(Configuration& config, XMLElement* memspec)
|
||||
void ConfigurationLoader::loadMemSpec(Configuration &config,
|
||||
XMLElement *memspec)
|
||||
{
|
||||
config.memSpec.MemoryId = queryStringParameter(memspec, "memoryId");
|
||||
config.memSpec.MemoryType = queryStringParameter(memspec, "memoryType");
|
||||
|
||||
std::cout << "Memtype: " << config.memSpec.MemoryType << std::endl;
|
||||
|
||||
if (config.memSpec.MemoryType == "DDR4")
|
||||
{
|
||||
if (config.memSpec.MemoryType == "DDR4") {
|
||||
loadDDR4(config, memspec);
|
||||
}
|
||||
else if (config.memSpec.MemoryType == "DDR3")
|
||||
{
|
||||
} else if (config.memSpec.MemoryType == "DDR3") {
|
||||
loadDDR3(config, memspec);
|
||||
}
|
||||
else if (config.memSpec.MemoryType == "LPDDR4")
|
||||
{
|
||||
} else if (config.memSpec.MemoryType == "LPDDR4") {
|
||||
loadLPDDR4(config, memspec);
|
||||
}
|
||||
else if (config.memSpec.MemoryType == "WIDEIO_SDR")
|
||||
{
|
||||
} else if (config.memSpec.MemoryType == "WIDEIO_SDR") {
|
||||
loadWideIO(config, memspec);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
reportFatal("ConfigurationLoader", "Unsupported DRAM type");
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigurationLoader::loadMCConfig(Configuration& config, string mcconfigUri)
|
||||
void ConfigurationLoader::loadMCConfig(Configuration &config,
|
||||
string mcconfigUri)
|
||||
{
|
||||
tinyxml2::XMLDocument doc;
|
||||
config.mcconfigUri = mcconfigUri;
|
||||
loadXML(mcconfigUri, doc);
|
||||
XMLElement* mcconfig = doc.FirstChildElement("mcconfig");
|
||||
XMLElement *mcconfig = doc.FirstChildElement("mcconfig");
|
||||
loadConfig(config, mcconfig);
|
||||
}
|
||||
|
||||
void ConfigurationLoader::loadMCConfig(Configuration& config, XMLElement* mcconfig)
|
||||
void ConfigurationLoader::loadMCConfig(Configuration &config,
|
||||
XMLElement *mcconfig)
|
||||
{
|
||||
if(mcconfig->Attribute("src"))
|
||||
{
|
||||
if (mcconfig->Attribute("src")) {
|
||||
XMLDocument doc;
|
||||
string src(mcconfig->Attribute("src"));
|
||||
config.mcconfigUri = src;
|
||||
loadXML(src, doc);
|
||||
loadMCConfig(config, doc.FirstChildElement("mcconfig"));
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
loadConfig(config, mcconfig);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void ConfigurationLoader::loadDDR3(Configuration& config, XMLElement* memspec)
|
||||
void ConfigurationLoader::loadDDR3(Configuration &config, XMLElement *memspec)
|
||||
{
|
||||
//MemArchitecture
|
||||
XMLElement* architecture = memspec->FirstChildElement("memarchitecturespec");
|
||||
XMLElement *architecture = memspec->FirstChildElement("memarchitecturespec");
|
||||
|
||||
config.memSpec.NumberOfBanks = queryUIntParameter(architecture, "nbrOfBanks");
|
||||
config.memSpec.NumberOfBankGroups = 1;
|
||||
@@ -174,13 +169,14 @@ void ConfigurationLoader::loadDDR3(Configuration& config, XMLElement* memspec)
|
||||
config.memSpec.nActivate = 4;
|
||||
config.memSpec.DataRate = queryUIntParameter(architecture, "dataRate");
|
||||
config.memSpec.NumberOfRows = queryUIntParameter(architecture, "nbrOfRows");
|
||||
config.memSpec.NumberOfColumns = queryUIntParameter(architecture, "nbrOfColumns");
|
||||
config.memSpec.NumberOfColumns = queryUIntParameter(architecture,
|
||||
"nbrOfColumns");
|
||||
config.memSpec.bitWidth = queryUIntParameter(architecture, "width");
|
||||
config.memSpec.DLL = true;
|
||||
config.memSpec.termination = true;
|
||||
|
||||
//MemTimings
|
||||
XMLElement* timings = memspec->FirstChildElement("memtimingspec");
|
||||
XMLElement *timings = memspec->FirstChildElement("memtimingspec");
|
||||
double clkMhz = queryDoubleParameter(timings, "clkMhz");
|
||||
config.memSpec.clk = FrequencyToClk(clkMhz);
|
||||
sc_time clk = config.memSpec.clk;
|
||||
@@ -211,13 +207,13 @@ void ConfigurationLoader::loadDDR3(Configuration& config, XMLElement* memspec)
|
||||
config.memSpec.tDQSCK = clk * queryUIntParameter(timings, "DQSCK");
|
||||
|
||||
config.memSpec.refreshTimings.clear();
|
||||
for (unsigned int i = 0; i < config.memSpec.NumberOfBanks; ++i)
|
||||
{
|
||||
config.memSpec.refreshTimings[Bank(i)] = RefreshTiming(config.memSpec.tRFC, config.memSpec.tREFI);
|
||||
for (unsigned int i = 0; i < config.memSpec.NumberOfBanks; ++i) {
|
||||
config.memSpec.refreshTimings[Bank(i)] = RefreshTiming(config.memSpec.tRFC,
|
||||
config.memSpec.tREFI);
|
||||
}
|
||||
|
||||
// Currents and Volatages: TODO Check if this is correct.
|
||||
XMLElement* powers = memspec->FirstChildElement("mempowerspec");
|
||||
XMLElement *powers = memspec->FirstChildElement("mempowerspec");
|
||||
config.memSpec.iDD0 = queryDoubleParameter(powers, "idd0");
|
||||
config.memSpec.iDD02 = queryDoubleParameter(powers, "idd0");
|
||||
config.memSpec.iDD2P0 = queryDoubleParameter(powers, "idd2p0");
|
||||
@@ -236,25 +232,27 @@ void ConfigurationLoader::loadDDR3(Configuration& config, XMLElement* memspec)
|
||||
}
|
||||
|
||||
|
||||
void ConfigurationLoader::loadDDR4(Configuration& config, XMLElement* memspec)
|
||||
void ConfigurationLoader::loadDDR4(Configuration &config, XMLElement *memspec)
|
||||
{
|
||||
//MemArchitecture
|
||||
XMLElement* architecture = memspec->FirstChildElement("memarchitecturespec");
|
||||
XMLElement *architecture = memspec->FirstChildElement("memarchitecturespec");
|
||||
|
||||
config.memSpec.NumberOfBanks = queryUIntParameter(architecture, "nbrOfBanks");
|
||||
config.memSpec.NumberOfBankGroups = queryUIntParameter(architecture, "nbrOfBankGroups");
|
||||
config.memSpec.NumberOfBankGroups = queryUIntParameter(architecture,
|
||||
"nbrOfBankGroups");
|
||||
config.memSpec.NumberOfRanks = queryUIntParameter(architecture, "nbrOfRanks");
|
||||
config.memSpec.BurstLength = queryUIntParameter(architecture, "burstLength");
|
||||
config.memSpec.nActivate = 4;
|
||||
config.memSpec.DataRate = queryUIntParameter(architecture, "dataRate");
|
||||
config.memSpec.NumberOfRows = queryUIntParameter(architecture, "nbrOfRows");
|
||||
config.memSpec.NumberOfColumns = queryUIntParameter(architecture, "nbrOfColumns");
|
||||
config.memSpec.NumberOfColumns = queryUIntParameter(architecture,
|
||||
"nbrOfColumns");
|
||||
config.memSpec.bitWidth = queryUIntParameter(architecture, "width");
|
||||
config.memSpec.DLL = true;
|
||||
config.memSpec.termination = true;
|
||||
|
||||
//MemTimings
|
||||
XMLElement* timings = memspec->FirstChildElement("memtimingspec");
|
||||
XMLElement *timings = memspec->FirstChildElement("memtimingspec");
|
||||
double clkMhz = queryDoubleParameter(timings, "clkMhz");
|
||||
config.memSpec.clk = FrequencyToClk(clkMhz);
|
||||
sc_time clk = config.memSpec.clk;
|
||||
@@ -285,13 +283,13 @@ void ConfigurationLoader::loadDDR4(Configuration& config, XMLElement* memspec)
|
||||
config.memSpec.tDQSCK = clk * queryUIntParameter(timings, "DQSCK");
|
||||
|
||||
config.memSpec.refreshTimings.clear();
|
||||
for (unsigned int i = 0; i < config.memSpec.NumberOfBanks; ++i)
|
||||
{
|
||||
config.memSpec.refreshTimings[Bank(i)] = RefreshTiming(config.memSpec.tRFC, config.memSpec.tREFI);
|
||||
for (unsigned int i = 0; i < config.memSpec.NumberOfBanks; ++i) {
|
||||
config.memSpec.refreshTimings[Bank(i)] = RefreshTiming(config.memSpec.tRFC,
|
||||
config.memSpec.tREFI);
|
||||
}
|
||||
|
||||
// Currents and Volatages:
|
||||
XMLElement* powers = memspec->FirstChildElement("mempowerspec");
|
||||
XMLElement *powers = memspec->FirstChildElement("mempowerspec");
|
||||
config.memSpec.iDD0 = queryDoubleParameter(powers, "idd0");
|
||||
config.memSpec.iDD02 = queryDoubleParameter(powers, "idd02");
|
||||
config.memSpec.iDD2P0 = queryDoubleParameter(powers, "idd2p0");
|
||||
@@ -310,10 +308,10 @@ void ConfigurationLoader::loadDDR4(Configuration& config, XMLElement* memspec)
|
||||
}
|
||||
|
||||
// TODO: fix this for LPDDR4
|
||||
void ConfigurationLoader::loadLPDDR4(Configuration& config, XMLElement* memspec)
|
||||
void ConfigurationLoader::loadLPDDR4(Configuration &config, XMLElement *memspec)
|
||||
{
|
||||
//MemArchitecture:
|
||||
XMLElement* architecture = memspec->FirstChildElement("memarchitecturespec");
|
||||
XMLElement *architecture = memspec->FirstChildElement("memarchitecturespec");
|
||||
|
||||
config.memSpec.NumberOfBanks = queryUIntParameter(architecture, "nbrOfBanks");
|
||||
config.memSpec.NumberOfBankGroups = 1;
|
||||
@@ -322,13 +320,14 @@ void ConfigurationLoader::loadLPDDR4(Configuration& config, XMLElement* memspec)
|
||||
config.memSpec.nActivate = 4;
|
||||
config.memSpec.DataRate = queryUIntParameter(architecture, "dataRate");
|
||||
config.memSpec.NumberOfRows = queryUIntParameter(architecture, "nbrOfRows");
|
||||
config.memSpec.NumberOfColumns = queryUIntParameter(architecture, "nbrOfColumns");
|
||||
config.memSpec.NumberOfColumns = queryUIntParameter(architecture,
|
||||
"nbrOfColumns");
|
||||
config.memSpec.bitWidth = queryUIntParameter(architecture, "width");
|
||||
config.memSpec.DLL = false; // TODO: Correct?
|
||||
config.memSpec.termination = true; // TODO: Correct?
|
||||
|
||||
//MemTimings
|
||||
XMLElement* timings = memspec->FirstChildElement("memtimingspec");
|
||||
XMLElement *timings = memspec->FirstChildElement("memtimingspec");
|
||||
double clkMhz = queryDoubleParameter(timings, "clkMhz");
|
||||
config.memSpec.clk = FrequencyToClk(clkMhz);
|
||||
sc_time clk = config.memSpec.clk;
|
||||
@@ -362,13 +361,13 @@ void ConfigurationLoader::loadLPDDR4(Configuration& config, XMLElement* memspec)
|
||||
config.memSpec.tDQSCK = clk * queryUIntParameter(timings, "DQSCK");
|
||||
|
||||
config.memSpec.refreshTimings.clear();
|
||||
for (unsigned int i = 0; i < config.memSpec.NumberOfBanks; ++i)
|
||||
{
|
||||
config.memSpec.refreshTimings[Bank(i)] = RefreshTiming(config.memSpec.tRFC, config.memSpec.tREFI);
|
||||
for (unsigned int i = 0; i < config.memSpec.NumberOfBanks; ++i) {
|
||||
config.memSpec.refreshTimings[Bank(i)] = RefreshTiming(config.memSpec.tRFC,
|
||||
config.memSpec.tREFI);
|
||||
}
|
||||
|
||||
// Currents and Volatages:
|
||||
XMLElement* powers = memspec->FirstChildElement("mempowerspec");
|
||||
XMLElement *powers = memspec->FirstChildElement("mempowerspec");
|
||||
config.memSpec.iDD0 = queryDoubleParameter(powers, "idd0");
|
||||
config.memSpec.iDD02 = queryDoubleParameter(powers, "idd02");
|
||||
config.memSpec.iDD2P0 = queryDoubleParameter(powers, "idd2p");
|
||||
@@ -386,10 +385,10 @@ void ConfigurationLoader::loadLPDDR4(Configuration& config, XMLElement* memspec)
|
||||
config.memSpec.vDD2 = queryDoubleParameter(powers, "vdd2");
|
||||
}
|
||||
|
||||
void ConfigurationLoader::loadWideIO(Configuration& config, XMLElement* memspec)
|
||||
void ConfigurationLoader::loadWideIO(Configuration &config, XMLElement *memspec)
|
||||
{
|
||||
//MemSpecification
|
||||
XMLElement* architecture = memspec->FirstChildElement("memarchitecturespec");
|
||||
XMLElement *architecture = memspec->FirstChildElement("memarchitecturespec");
|
||||
|
||||
config.memSpec.NumberOfBanks = queryUIntParameter(architecture, "nbrOfBanks");
|
||||
config.memSpec.NumberOfBankGroups = 1;
|
||||
@@ -398,13 +397,14 @@ void ConfigurationLoader::loadWideIO(Configuration& config, XMLElement* memspec)
|
||||
config.memSpec.nActivate = 2;
|
||||
config.memSpec.DataRate = queryUIntParameter(architecture, "dataRate");
|
||||
config.memSpec.NumberOfRows = queryUIntParameter(architecture, "nbrOfRows");
|
||||
config.memSpec.NumberOfColumns = queryUIntParameter(architecture, "nbrOfColumns");
|
||||
config.memSpec.NumberOfColumns = queryUIntParameter(architecture,
|
||||
"nbrOfColumns");
|
||||
config.memSpec.bitWidth = queryUIntParameter(architecture, "width");
|
||||
config.memSpec.DLL = false;
|
||||
config.memSpec.termination = false;
|
||||
|
||||
//MemTimings
|
||||
XMLElement* timings = memspec->FirstChildElement("memtimingspec");
|
||||
XMLElement *timings = memspec->FirstChildElement("memtimingspec");
|
||||
double clkMhz = queryDoubleParameter(timings, "clkMhz");
|
||||
config.memSpec.clk = FrequencyToClk(clkMhz);
|
||||
sc_time clk = config.memSpec.clk;
|
||||
@@ -434,13 +434,13 @@ void ConfigurationLoader::loadWideIO(Configuration& config, XMLElement* memspec)
|
||||
config.memSpec.tREFI = clk * queryUIntParameter(timings, "REFI");
|
||||
|
||||
config.memSpec.refreshTimings.clear();
|
||||
for (unsigned int i = 0; i < config.memSpec.NumberOfBanks; ++i)
|
||||
{
|
||||
config.memSpec.refreshTimings[Bank(i)] = RefreshTiming(config.memSpec.tRFC, config.memSpec.tREFI);
|
||||
for (unsigned int i = 0; i < config.memSpec.NumberOfBanks; ++i) {
|
||||
config.memSpec.refreshTimings[Bank(i)] = RefreshTiming(config.memSpec.tRFC,
|
||||
config.memSpec.tREFI);
|
||||
}
|
||||
|
||||
// Currents and Volatages:
|
||||
XMLElement* powers = memspec->FirstChildElement("mempowerspec");
|
||||
XMLElement *powers = memspec->FirstChildElement("mempowerspec");
|
||||
config.memSpec.iDD0 = queryDoubleParameter(powers, "idd0");
|
||||
config.memSpec.iDD02 = queryDoubleParameter(powers, "idd02");
|
||||
config.memSpec.iDD2P0 = queryDoubleParameter(powers, "idd2p0");
|
||||
|
||||
@@ -46,27 +46,31 @@ class ConfigurationLoader
|
||||
{
|
||||
public:
|
||||
|
||||
static void loadMCConfig(Configuration& config, std::string amconfigUri);
|
||||
static void loadMCConfig(Configuration& config, tinyxml2::XMLElement* mcconfig);
|
||||
static void loadMCConfig(Configuration &config, std::string amconfigUri);
|
||||
static void loadMCConfig(Configuration &config, tinyxml2::XMLElement *mcconfig);
|
||||
|
||||
static void loadSimConfig(Configuration& config, std::string simconfigUri);
|
||||
static void loadSimConfig(Configuration& config,tinyxml2::XMLElement* simconfig);
|
||||
static void loadSimConfig(Configuration &config, std::string simconfigUri);
|
||||
static void loadSimConfig(Configuration &config,
|
||||
tinyxml2::XMLElement *simconfig);
|
||||
|
||||
static void loadMemSpec(Configuration& config, std::string memspecUri);
|
||||
static void loadMemSpec(Configuration& config, tinyxml2::XMLElement* memspec);
|
||||
static void loadMemSpec(Configuration &config, std::string memspecUri);
|
||||
static void loadMemSpec(Configuration &config, tinyxml2::XMLElement *memspec);
|
||||
|
||||
static void loadTemperatureSimConfig(Configuration &config, std::string simconfigUri);
|
||||
static void loadTemperatureSimConfig(Configuration& config, tinyxml2::XMLElement *simconfig);
|
||||
static void loadTemperatureSimConfig(Configuration &config,
|
||||
std::string simconfigUri);
|
||||
static void loadTemperatureSimConfig(Configuration &config,
|
||||
tinyxml2::XMLElement *simconfig);
|
||||
private:
|
||||
ConfigurationLoader(){}
|
||||
static void loadConfig(Configuration& config, tinyxml2::XMLElement* configNode);
|
||||
static void loadConfigFromUri(Configuration &config, std::string uri, std::string first_element);
|
||||
ConfigurationLoader() {}
|
||||
static void loadConfig(Configuration &config, tinyxml2::XMLElement *configNode);
|
||||
static void loadConfigFromUri(Configuration &config, std::string uri,
|
||||
std::string first_element);
|
||||
|
||||
//specific loader
|
||||
static void loadDDR3(Configuration& config, tinyxml2::XMLElement* memspec);
|
||||
static void loadDDR4(Configuration& config, tinyxml2::XMLElement* memspec);
|
||||
static void loadLPDDR4(Configuration& config, tinyxml2::XMLElement* memspec);
|
||||
static void loadWideIO(Configuration& config, tinyxml2::XMLElement* memspec);
|
||||
static void loadDDR3(Configuration &config, tinyxml2::XMLElement *memspec);
|
||||
static void loadDDR4(Configuration &config, tinyxml2::XMLElement *memspec);
|
||||
static void loadLPDDR4(Configuration &config, tinyxml2::XMLElement *memspec);
|
||||
static void loadWideIO(Configuration &config, tinyxml2::XMLElement *memspec);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -42,28 +42,24 @@
|
||||
#include "../../../common/dramExtension.h"
|
||||
|
||||
|
||||
struct RefreshTiming
|
||||
{
|
||||
struct RefreshTiming {
|
||||
RefreshTiming() {}
|
||||
RefreshTiming(sc_time tRFC, sc_time tREFI) : tRFC(tRFC), tREFI(tREFI) {}
|
||||
sc_time tRFC;
|
||||
sc_time tREFI;
|
||||
sc_time tRFC;
|
||||
sc_time tREFI;
|
||||
};
|
||||
|
||||
struct MemSpec
|
||||
{
|
||||
struct MemSpec {
|
||||
MemSpec()
|
||||
{
|
||||
{
|
||||
//default DDR4
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<Bank>& getBanks() const
|
||||
const std::vector<Bank> &getBanks() const
|
||||
{
|
||||
static std::vector<Bank> banks;
|
||||
if (banks.size() == 0)
|
||||
{
|
||||
for (unsigned int i = 0; i < NumberOfBanks; i++)
|
||||
{
|
||||
if (banks.size() == 0) {
|
||||
for (unsigned int i = 0; i < NumberOfBanks; i++) {
|
||||
banks.push_back(Bank(i));
|
||||
}
|
||||
}
|
||||
@@ -87,34 +83,34 @@ struct MemSpec
|
||||
bool termination;
|
||||
|
||||
// Memspec Variables:
|
||||
sc_time clk;
|
||||
sc_time tRP; //precharge-time (pre -> act same bank)
|
||||
sc_time tRPAB; //precharge-all time only for LPDDR4
|
||||
sc_time tRAS; //active-time (act -> pre same bank)
|
||||
sc_time tRC; //RAS-cycle-time (min time bw 2 succesive ACT to same bank)
|
||||
sc_time tCCD_S; //max(bl, tCCD) is relevant for rd->rd
|
||||
sc_time tCCD_L;
|
||||
sc_time tRTP; //Read to precharge
|
||||
sc_time tRRD_S; //min time bw 2 succesive ACT to different banks (different bank group)
|
||||
sc_time tRRD_L; //.. (same bank group)
|
||||
sc_time tRCD; //act -> read/write
|
||||
sc_time tNAW; //n activate window
|
||||
sc_time tRL; //read latency (read command start to data strobe)
|
||||
sc_time tWL; //write latency
|
||||
sc_time tWR; //write recovery (write to precharge)
|
||||
sc_time tWTR_S; //write to read (different bank group)
|
||||
sc_time tWTR_L; //.. (same bank group)
|
||||
sc_time tCKESR; //min time in sref
|
||||
sc_time tCKE; //min time in pdna or pdnp
|
||||
sc_time tXP; //min delay to row access command after pdnpx pdnax
|
||||
sc_time tXPDLL; //min delay to row access command after pdnpx pdnax for dll commands
|
||||
sc_time tXSR; //min delay to row access command after srefx
|
||||
sc_time tXSRDLL; //min delay to row access command after srefx for dll commands
|
||||
sc_time tAL; //additive delay (delayed execution in dram)
|
||||
sc_time clk;
|
||||
sc_time tRP; //precharge-time (pre -> act same bank)
|
||||
sc_time tRPAB; //precharge-all time only for LPDDR4
|
||||
sc_time tRAS; //active-time (act -> pre same bank)
|
||||
sc_time tRC; //RAS-cycle-time (min time bw 2 succesive ACT to same bank)
|
||||
sc_time tCCD_S; //max(bl, tCCD) is relevant for rd->rd
|
||||
sc_time tCCD_L;
|
||||
sc_time tRTP; //Read to precharge
|
||||
sc_time tRRD_S; //min time bw 2 succesive ACT to different banks (different bank group)
|
||||
sc_time tRRD_L; //.. (same bank group)
|
||||
sc_time tRCD; //act -> read/write
|
||||
sc_time tNAW; //n activate window
|
||||
sc_time tRL; //read latency (read command start to data strobe)
|
||||
sc_time tWL; //write latency
|
||||
sc_time tWR; //write recovery (write to precharge)
|
||||
sc_time tWTR_S; //write to read (different bank group)
|
||||
sc_time tWTR_L; //.. (same bank group)
|
||||
sc_time tCKESR; //min time in sref
|
||||
sc_time tCKE; //min time in pdna or pdnp
|
||||
sc_time tXP; //min delay to row access command after pdnpx pdnax
|
||||
sc_time tXPDLL; //min delay to row access command after pdnpx pdnax for dll commands
|
||||
sc_time tXSR; //min delay to row access command after srefx
|
||||
sc_time tXSRDLL; //min delay to row access command after srefx for dll commands
|
||||
sc_time tAL; //additive delay (delayed execution in dram)
|
||||
sc_time tDQSCK;
|
||||
|
||||
sc_time tRFC; //min ref->act delay
|
||||
sc_time tREFI; //auto refresh must be issued at an average periodic interval tREFI
|
||||
sc_time tRFC; //min ref->act delay
|
||||
sc_time tREFI; //auto refresh must be issued at an average periodic interval tREFI
|
||||
|
||||
// Currents and Voltages:
|
||||
double iDD0;
|
||||
@@ -143,11 +139,18 @@ struct MemSpec
|
||||
double vDD2;
|
||||
|
||||
|
||||
std::map<Bank, RefreshTiming> refreshTimings;//ensure that map is populated completely in memspecloader
|
||||
std::map<Bank, RefreshTiming>
|
||||
refreshTimings;//ensure that map is populated completely in memspecloader
|
||||
|
||||
//act and read/write commands remain for this timespan in history
|
||||
sc_time tActHistory(){return tNAW;}
|
||||
sc_time tDataStrobeHistory(){return tWTR_L;}
|
||||
//act and read/write commands remain for this timespan in history
|
||||
sc_time tActHistory()
|
||||
{
|
||||
return tNAW;
|
||||
}
|
||||
sc_time tDataStrobeHistory()
|
||||
{
|
||||
return tWTR_L;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* MemSpec_H_ */
|
||||
|
||||
@@ -79,8 +79,8 @@ struct TemperatureSimConfig {
|
||||
printDebugMessage("Power Info File: " + powerInfoFile);
|
||||
|
||||
powerInfoFile = pathToResources
|
||||
+ "/configs/thermalsim/"
|
||||
+ powerInfoFile;
|
||||
+ "/configs/thermalsim/"
|
||||
+ powerInfoFile;
|
||||
|
||||
// Load the XML file into memory and parse it
|
||||
tinyxml2::XMLDocument xml;
|
||||
@@ -94,7 +94,8 @@ struct TemperatureSimConfig {
|
||||
SC_REPORT_FATAL("Temperature Sim Config", errormsg.c_str());
|
||||
}
|
||||
|
||||
for (tinyxml2::XMLElement *e = powInfoElem->FirstChildElement(); e != NULL; e = e->NextSiblingElement()) {
|
||||
for (tinyxml2::XMLElement *e = powInfoElem->FirstChildElement(); e != NULL;
|
||||
e = e->NextSiblingElement()) {
|
||||
|
||||
// Load initial power values for all devices
|
||||
std::string init_pow_str = e->Attribute("init_pow");
|
||||
@@ -114,17 +115,20 @@ struct TemperatureSimConfig {
|
||||
{
|
||||
int i = 0;
|
||||
for (auto e : powerInitialValues) {
|
||||
printDebugMessage("powerInitialValues[" + std::to_string(i++) + "]: " + std::to_string(e));
|
||||
printDebugMessage("powerInitialValues[" + std::to_string(
|
||||
i++) + "]: " + std::to_string(e));
|
||||
}
|
||||
i = 0;
|
||||
for (auto e : powerThresholds) {
|
||||
printDebugMessage("powerThreshold[" + std::to_string(i++) + "]: " + std::to_string(e));
|
||||
printDebugMessage("powerThreshold[" + std::to_string(i++) + "]: " +
|
||||
std::to_string(e));
|
||||
}
|
||||
}
|
||||
|
||||
void printDebugMessage(std::string message)
|
||||
{
|
||||
DebugManager::getInstance().printDebugMessage("Temperature Sim Config", message);
|
||||
DebugManager::getInstance().printDebugMessage("Temperature Sim Config",
|
||||
message);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -42,89 +42,87 @@
|
||||
#include "../../Command.h"
|
||||
|
||||
|
||||
enum class PowerDownState
|
||||
{
|
||||
Awake, AwakeForRefresh, PDNActive, PDNPrecharge, PDNSelfRefresh
|
||||
enum class PowerDownState {
|
||||
Awake, AwakeForRefresh, PDNActive, PDNPrecharge, PDNSelfRefresh
|
||||
};
|
||||
|
||||
class IPowerDownManager
|
||||
{
|
||||
public:
|
||||
virtual ~IPowerDownManager() {}
|
||||
virtual ~IPowerDownManager() {}
|
||||
|
||||
virtual void sleep(Bank bank, sc_time time) = 0;
|
||||
virtual void triggerSleep(Bank bank, sc_time time) = 0;
|
||||
virtual void sleep(Bank bank, sc_time time) = 0;
|
||||
virtual void triggerSleep(Bank bank, sc_time time) = 0;
|
||||
|
||||
virtual void wakeUp(Bank bank, sc_time time) = 0;
|
||||
virtual void wakeUpForRefresh(Bank bank, sc_time time) = 0;
|
||||
virtual void wakeUp(Bank bank, sc_time time) = 0;
|
||||
virtual void wakeUpForRefresh(Bank bank, sc_time time) = 0;
|
||||
|
||||
virtual bool isInSelfRefresh(Bank bank) = 0;
|
||||
virtual bool isInSelfRefresh(Bank bank) = 0;
|
||||
|
||||
protected:
|
||||
Command getSleepCommand(PowerDownState state);
|
||||
Command getWakeUpCommand(PowerDownState state);
|
||||
Command getSleepCommand(PowerDownState state);
|
||||
Command getWakeUpCommand(PowerDownState state);
|
||||
|
||||
};
|
||||
|
||||
inline Command IPowerDownManager::getSleepCommand(PowerDownState state)
|
||||
{
|
||||
Command cmd(Command::NOP);
|
||||
switch (state)
|
||||
{
|
||||
case PowerDownState::PDNActive:
|
||||
cmd = Command::PDNA;
|
||||
break;
|
||||
case PowerDownState::PDNPrecharge:
|
||||
cmd = Command::PDNP;
|
||||
break;
|
||||
case PowerDownState::PDNSelfRefresh:
|
||||
cmd = Command::SREF;
|
||||
break;
|
||||
default:
|
||||
SC_REPORT_FATAL("In PowerDownManager sendPowerdownBegin", "invalid powerDownState");
|
||||
break;
|
||||
}
|
||||
return cmd;
|
||||
Command cmd(Command::NOP);
|
||||
switch (state) {
|
||||
case PowerDownState::PDNActive:
|
||||
cmd = Command::PDNA;
|
||||
break;
|
||||
case PowerDownState::PDNPrecharge:
|
||||
cmd = Command::PDNP;
|
||||
break;
|
||||
case PowerDownState::PDNSelfRefresh:
|
||||
cmd = Command::SREF;
|
||||
break;
|
||||
default:
|
||||
SC_REPORT_FATAL("In PowerDownManager sendPowerdownBegin",
|
||||
"invalid powerDownState");
|
||||
break;
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
inline Command IPowerDownManager::getWakeUpCommand(PowerDownState state)
|
||||
|
||||
{
|
||||
Command cmd(Command::NOP);
|
||||
switch (state)
|
||||
{
|
||||
case PowerDownState::PDNActive:
|
||||
cmd = Command::PDNAX;
|
||||
break;
|
||||
case PowerDownState::PDNPrecharge:
|
||||
cmd = Command::PDNPX;
|
||||
break;
|
||||
case PowerDownState::PDNSelfRefresh:
|
||||
cmd = Command::SREFX;
|
||||
break;
|
||||
default:
|
||||
SC_REPORT_FATAL("In PowerDownManager sendPowerdownEnd", "invalid powerDownState");
|
||||
}
|
||||
return cmd;
|
||||
Command cmd(Command::NOP);
|
||||
switch (state) {
|
||||
case PowerDownState::PDNActive:
|
||||
cmd = Command::PDNAX;
|
||||
break;
|
||||
case PowerDownState::PDNPrecharge:
|
||||
cmd = Command::PDNPX;
|
||||
break;
|
||||
case PowerDownState::PDNSelfRefresh:
|
||||
cmd = Command::SREFX;
|
||||
break;
|
||||
default:
|
||||
SC_REPORT_FATAL("In PowerDownManager sendPowerdownEnd",
|
||||
"invalid powerDownState");
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
inline std::string powerDownStateToString(PowerDownState powerDownState)
|
||||
{
|
||||
switch (powerDownState)
|
||||
{
|
||||
case PowerDownState::Awake:
|
||||
return "Awake";
|
||||
case PowerDownState::AwakeForRefresh:
|
||||
return "Awake for refresh";
|
||||
case PowerDownState::PDNActive:
|
||||
return "PDN Active";
|
||||
case PowerDownState::PDNPrecharge:
|
||||
return "PDN Precharged";
|
||||
case PowerDownState::PDNSelfRefresh:
|
||||
return "PDN Self refresh";
|
||||
default:
|
||||
return "unknown state";
|
||||
}
|
||||
switch (powerDownState) {
|
||||
case PowerDownState::Awake:
|
||||
return "Awake";
|
||||
case PowerDownState::AwakeForRefresh:
|
||||
return "Awake for refresh";
|
||||
case PowerDownState::PDNActive:
|
||||
return "PDN Active";
|
||||
case PowerDownState::PDNPrecharge:
|
||||
return "PDN Precharged";
|
||||
case PowerDownState::PDNSelfRefresh:
|
||||
return "PDN Self refresh";
|
||||
default:
|
||||
return "unknown state";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -48,8 +48,8 @@
|
||||
class NoPowerDown: public IPowerDownManager
|
||||
{
|
||||
public:
|
||||
NoPowerDown(){}
|
||||
virtual ~NoPowerDown(){}
|
||||
NoPowerDown() {}
|
||||
virtual ~NoPowerDown() {}
|
||||
|
||||
virtual void triggerSleep(Bank bank, sc_time time) override;
|
||||
virtual void sleep(Bank bank, sc_time time) override;
|
||||
|
||||
@@ -48,12 +48,12 @@ using namespace tlm;
|
||||
using namespace std;
|
||||
|
||||
|
||||
PowerDownManager::PowerDownManager(sc_module_name /*name*/, ControllerCore& controller) :
|
||||
controllerCore(controller)
|
||||
PowerDownManager::PowerDownManager(sc_module_name /*name*/,
|
||||
ControllerCore &controller) :
|
||||
controllerCore(controller)
|
||||
{
|
||||
powerDownState = PowerDownState::Awake;
|
||||
for (Bank bank : controller.getBanks())
|
||||
{
|
||||
for (Bank bank : controller.getBanks()) {
|
||||
setUpDummy(powerDownPayloads[bank], bank);
|
||||
}
|
||||
//controllerCore.controller.send(PDNTrigger, sc_time_stamp(), powerDownPayloads[Bank(0)]);
|
||||
@@ -71,35 +71,31 @@ void PowerDownManager::sleep(Bank /*bank*/, sc_time time)
|
||||
|
||||
PowerDownState state = powerDownState;
|
||||
|
||||
if (state == PowerDownState::Awake) //coming from active
|
||||
{
|
||||
state = controllerCore.state->rowBufferStates->allRowBuffersAreClosed() ? PowerDownState::PDNPrecharge : PowerDownState::PDNActive;
|
||||
}
|
||||
else if (state == PowerDownState::AwakeForRefresh) //coming from refresh interrupting power down
|
||||
{
|
||||
if (state == PowerDownState::Awake) { //coming from active
|
||||
state = controllerCore.state->rowBufferStates->allRowBuffersAreClosed() ?
|
||||
PowerDownState::PDNPrecharge : PowerDownState::PDNActive;
|
||||
} else if (state ==
|
||||
PowerDownState::AwakeForRefresh) { //coming from refresh interrupting power down
|
||||
sc_assert(controllerCore.state->rowBufferStates->allRowBuffersAreClosed());
|
||||
|
||||
if (controllerCore.state->getLastCommand(Command::PDNA).getStart()
|
||||
>= controllerCore.state->getLastCommand(Command::PDNP).getStart())
|
||||
state = PowerDownState::PDNPrecharge;
|
||||
else
|
||||
{
|
||||
else {
|
||||
state = PowerDownState::PDNSelfRefresh;
|
||||
}
|
||||
}
|
||||
|
||||
Command cmd = IPowerDownManager::getSleepCommand(state);
|
||||
ScheduledCommand pdn(cmd, time, getMinExecutionTimeForPowerDownCmd(cmd),
|
||||
DramExtension::getExtension(powerDownPayloads[Bank(0)]));
|
||||
DramExtension::getExtension(powerDownPayloads[Bank(0)]));
|
||||
|
||||
controllerCore.getCommandChecker(cmd).delayToSatisfyConstraints(pdn);
|
||||
|
||||
if (state != PowerDownState::PDNSelfRefresh && controllerCore.refreshManager->hasCollision(pdn))
|
||||
{
|
||||
if (state != PowerDownState::PDNSelfRefresh
|
||||
&& controllerCore.refreshManager->hasCollision(pdn)) {
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
setPowerDownState(state);
|
||||
sendPowerDownPayload(pdn);
|
||||
}
|
||||
@@ -107,86 +103,95 @@ void PowerDownManager::sleep(Bank /*bank*/, sc_time time)
|
||||
|
||||
void PowerDownManager::wakeUp(Bank bank, sc_time time)
|
||||
{
|
||||
printDebugMessage("Waking up at " + time.to_string() + " current power down state is " + powerDownStateToString(powerDownState));
|
||||
printDebugMessage("Waking up at " + time.to_string() +
|
||||
" current power down state is " + powerDownStateToString(powerDownState));
|
||||
|
||||
if (isAwakeForRefresh()) //Request enters system during Refresh
|
||||
{
|
||||
if (isAwakeForRefresh()) { //Request enters system during Refresh
|
||||
setPowerDownState(PowerDownState::Awake);
|
||||
}
|
||||
else if (isInPowerDown()) //Request wakes up power down
|
||||
{
|
||||
} else if (isInPowerDown()) { //Request wakes up power down
|
||||
Command cmd = IPowerDownManager::getWakeUpCommand(powerDownState);
|
||||
ScheduledCommand pdn(cmd, time, getExecutionTime(cmd, powerDownPayloads[Bank(0)]),
|
||||
DramExtension::getExtension(powerDownPayloads[Bank(0)]));
|
||||
ScheduledCommand pdn(cmd, time, getExecutionTime(cmd,
|
||||
powerDownPayloads[Bank(0)]),
|
||||
DramExtension::getExtension(powerDownPayloads[Bank(0)]));
|
||||
controllerCore.getCommandChecker(cmd).delayToSatisfyConstraints(pdn);
|
||||
|
||||
if (cmd == Command::SREFX) {
|
||||
// Leaving Self Refresh. Plan the next refresh.
|
||||
controllerCore.refreshManager->reInitialize(bank, pdn.getEnd());
|
||||
printDebugMessage("Waking up. Leaving Self Refresh at " + time.to_string() + " next refresh planned to " + pdn.getEnd().to_string());
|
||||
printDebugMessage("Waking up. Leaving Self Refresh at " + time.to_string() +
|
||||
" next refresh planned to " + pdn.getEnd().to_string());
|
||||
}
|
||||
|
||||
setPowerDownState(PowerDownState::Awake);
|
||||
|
||||
printDebugMessage("Sending power down exit command " + commandToString(cmd) + " on all banks");
|
||||
printDebugMessage("Sending power down exit command " + commandToString(
|
||||
cmd) + " on all banks");
|
||||
sendPowerDownPayload(pdn);
|
||||
}
|
||||
|
||||
printDebugMessage("Awaken at " + time.to_string() + " current power down state is " + powerDownStateToString(powerDownState));
|
||||
printDebugMessage("Awaken at " + time.to_string() +
|
||||
" current power down state is " + powerDownStateToString(powerDownState));
|
||||
}
|
||||
|
||||
void PowerDownManager::wakeUpForRefresh(Bank /*bank*/, sc_time time)
|
||||
{
|
||||
printDebugMessage("Waking up for refresh at " + time.to_string() + " current power down state is " + powerDownStateToString(powerDownState));
|
||||
printDebugMessage("Waking up for refresh at " + time.to_string() +
|
||||
" current power down state is " + powerDownStateToString(powerDownState));
|
||||
|
||||
if (isInPowerDown())
|
||||
{
|
||||
if (isInPowerDown()) {
|
||||
Command cmd = IPowerDownManager::getWakeUpCommand(powerDownState);
|
||||
ScheduledCommand pdn(cmd, time, getExecutionTime(cmd, powerDownPayloads[Bank(0)]),
|
||||
DramExtension::getExtension(powerDownPayloads[Bank(0)]));
|
||||
ScheduledCommand pdn(cmd, time, getExecutionTime(cmd,
|
||||
powerDownPayloads[Bank(0)]),
|
||||
DramExtension::getExtension(powerDownPayloads[Bank(0)]));
|
||||
|
||||
setPowerDownState(PowerDownState::AwakeForRefresh);
|
||||
|
||||
printDebugMessage("Sending power down exit command " + commandToString(cmd) + " on all banks");
|
||||
printDebugMessage("Sending power down exit command " + commandToString(
|
||||
cmd) + " on all banks");
|
||||
sendPowerDownPayload(pdn);
|
||||
}
|
||||
|
||||
printDebugMessage("Awaken for refresh at " + time.to_string() + " current power down state is " + powerDownStateToString(powerDownState));
|
||||
printDebugMessage("Awaken for refresh at " + time.to_string() +
|
||||
" current power down state is " + powerDownStateToString(powerDownState));
|
||||
}
|
||||
|
||||
void PowerDownManager::sendPowerDownPayload(ScheduledCommand& pdnToSend)
|
||||
void PowerDownManager::sendPowerDownPayload(ScheduledCommand &pdnToSend)
|
||||
{
|
||||
controllerCore.state->bus.moveCommandToNextFreeSlot(pdnToSend);
|
||||
for (size_t bank = 1; bank < controllerCore.getBanks().size(); bank++)
|
||||
{
|
||||
tlm_generic_payload& payloadToSend = powerDownPayloads[bank];
|
||||
for (size_t bank = 1; bank < controllerCore.getBanks().size(); bank++) {
|
||||
tlm_generic_payload &payloadToSend = powerDownPayloads[bank];
|
||||
|
||||
ScheduledCommand pdn(pdnToSend.getCommand(), pdnToSend.getStart(), pdnToSend.getExecutionTime(), DramExtension::getExtension(payloadToSend));
|
||||
ScheduledCommand pdn(pdnToSend.getCommand(), pdnToSend.getStart(),
|
||||
pdnToSend.getExecutionTime(), DramExtension::getExtension(payloadToSend));
|
||||
controllerCore.state->change(pdn);
|
||||
|
||||
}
|
||||
controllerCore.state->change(pdnToSend);
|
||||
controllerCore.controller.send(pdnToSend, powerDownPayloads[Bank(0)]);
|
||||
printDebugMessage("Sending power down command " + commandToString(pdnToSend.getCommand()) + " on bank " + to_string(pdnToSend.getBank().ID()) + " start time " + pdnToSend.getStart().to_string() + " end time " + pdnToSend.getEnd().to_string());
|
||||
printDebugMessage("Sending power down command " + commandToString(
|
||||
pdnToSend.getCommand()) + " on bank " + to_string(pdnToSend.getBank().ID()) +
|
||||
" start time " + pdnToSend.getStart().to_string() + " end time " +
|
||||
pdnToSend.getEnd().to_string());
|
||||
|
||||
}
|
||||
|
||||
void PowerDownManager::setPowerDownState(PowerDownState state)
|
||||
{
|
||||
powerDownState = state;
|
||||
printDebugMessage("Is now in state " + powerDownStateToString(powerDownState) + " on all banks");
|
||||
printDebugMessage("Is now in state " + powerDownStateToString(
|
||||
powerDownState) + " on all banks");
|
||||
}
|
||||
|
||||
bool PowerDownManager::isInPowerDown()
|
||||
{
|
||||
return (powerDownState == PowerDownState::PDNActive || powerDownState == PowerDownState::PDNPrecharge
|
||||
return (powerDownState == PowerDownState::PDNActive
|
||||
|| powerDownState == PowerDownState::PDNPrecharge
|
||||
|| powerDownState == PowerDownState::PDNSelfRefresh);
|
||||
}
|
||||
|
||||
bool PowerDownManager::canSleep()
|
||||
{
|
||||
for (Bank bank : controllerCore.getBanks())
|
||||
{
|
||||
for (Bank bank : controllerCore.getBanks()) {
|
||||
if (!controllerCore.numberOfPayloads[bank] == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ class ControllerCore;
|
||||
class PowerDownManager: public IPowerDownManager, public sc_module
|
||||
{
|
||||
public:
|
||||
PowerDownManager(sc_module_name /*name*/, ControllerCore& controllerCore);
|
||||
PowerDownManager(sc_module_name /*name*/, ControllerCore &controllerCore);
|
||||
virtual ~PowerDownManager();
|
||||
|
||||
virtual void triggerSleep(Bank bank, sc_time time) override;
|
||||
@@ -55,7 +55,7 @@ public:
|
||||
virtual bool isInSelfRefresh(Bank bank) override;
|
||||
|
||||
protected:
|
||||
void sendPowerDownPayload(ScheduledCommand& pdnToSend);
|
||||
void sendPowerDownPayload(ScheduledCommand &pdnToSend);
|
||||
bool isInPowerDown();
|
||||
void setPowerDownState(PowerDownState state);
|
||||
bool canSleep();
|
||||
@@ -63,7 +63,7 @@ protected:
|
||||
|
||||
PowerDownState powerDownState;
|
||||
std::map<Bank, tlm::tlm_generic_payload> powerDownPayloads;
|
||||
ControllerCore& controllerCore;
|
||||
ControllerCore &controllerCore;
|
||||
void printDebugMessage(std::string message);
|
||||
};
|
||||
|
||||
|
||||
@@ -42,10 +42,10 @@
|
||||
|
||||
using namespace tlm;
|
||||
|
||||
PowerDownManagerBankwise::PowerDownManagerBankwise(sc_module_name /*name*/, ControllerCore& controllerCore) : controllerCore(controllerCore)
|
||||
PowerDownManagerBankwise::PowerDownManagerBankwise(sc_module_name /*name*/,
|
||||
ControllerCore &controllerCore) : controllerCore(controllerCore)
|
||||
{
|
||||
for (Bank bank : controllerCore.getBanks())
|
||||
{
|
||||
for (Bank bank : controllerCore.getBanks()) {
|
||||
setUpDummy(powerDownPayloads[bank], bank);
|
||||
powerDownStates[bank] = PowerDownState::Awake;
|
||||
//controllerCore.controller.send(PDNTrigger, sc_time_stamp(), powerDownPayloads[bank]);
|
||||
@@ -57,36 +57,33 @@ void PowerDownManagerBankwise::sleep(Bank bank, sc_time time)
|
||||
if (!canSleep(bank) || isInPowerDown(bank))
|
||||
return;
|
||||
|
||||
tlm_generic_payload& payload = powerDownPayloads[bank];
|
||||
tlm_generic_payload &payload = powerDownPayloads[bank];
|
||||
|
||||
PowerDownState state = powerDownStates[bank];
|
||||
if (state == PowerDownState::Awake) //coming from active
|
||||
{
|
||||
state = controllerCore.state->rowBufferStates->rowBufferIsOpen(bank) ? PowerDownState::PDNActive : PowerDownState::PDNPrecharge;
|
||||
}
|
||||
else if (state == PowerDownState::AwakeForRefresh) //coming from refresh interrupting power down
|
||||
{
|
||||
if (state == PowerDownState::Awake) { //coming from active
|
||||
state = controllerCore.state->rowBufferStates->rowBufferIsOpen(
|
||||
bank) ? PowerDownState::PDNActive : PowerDownState::PDNPrecharge;
|
||||
} else if (state ==
|
||||
PowerDownState::AwakeForRefresh) { //coming from refresh interrupting power down
|
||||
sc_assert(!controllerCore.state->rowBufferStates->rowBufferIsOpen(bank));
|
||||
|
||||
if (controllerCore.state->getLastCommand(Command::PDNA, bank).getStart()
|
||||
>= controllerCore.state->getLastCommand(Command::PDNP, bank).getStart())
|
||||
state = PowerDownState::PDNPrecharge;
|
||||
else
|
||||
{
|
||||
else {
|
||||
state = PowerDownState::PDNSelfRefresh;
|
||||
}
|
||||
}
|
||||
|
||||
Command cmd = IPowerDownManager::getSleepCommand(state);
|
||||
ScheduledCommand pdn(cmd, time, getMinExecutionTimeForPowerDownCmd(cmd), DramExtension::getExtension(payload));
|
||||
ScheduledCommand pdn(cmd, time, getMinExecutionTimeForPowerDownCmd(cmd),
|
||||
DramExtension::getExtension(payload));
|
||||
controllerCore.getCommandChecker(cmd).delayToSatisfyConstraints(pdn);
|
||||
|
||||
if (state != PowerDownState::PDNSelfRefresh && controllerCore.refreshManager->hasCollision(pdn))
|
||||
{
|
||||
if (state != PowerDownState::PDNSelfRefresh
|
||||
&& controllerCore.refreshManager->hasCollision(pdn)) {
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
setPowerDownState(state, bank);
|
||||
sendPowerDownPayload(pdn);
|
||||
}
|
||||
@@ -94,37 +91,50 @@ void PowerDownManagerBankwise::sleep(Bank bank, sc_time time)
|
||||
|
||||
void PowerDownManagerBankwise::wakeUp(Bank bank, sc_time time)
|
||||
{
|
||||
printDebugMessage("Waking up on bank " + to_string(bank.ID()) + " at " + time.to_string() + " current power down state is " + powerDownStateToString(powerDownStates[bank]));
|
||||
printDebugMessage("Waking up on bank " + to_string(bank.ID()) + " at " +
|
||||
time.to_string() + " current power down state is " + powerDownStateToString(
|
||||
powerDownStates[bank]));
|
||||
|
||||
if (isAwakeForRefresh(bank)) {
|
||||
printDebugMessage("It was already awake for refresh on bank " + to_string(bank.ID()) + " at " + time.to_string());
|
||||
printDebugMessage("It was already awake for refresh on bank " + to_string(
|
||||
bank.ID()) + " at " + time.to_string());
|
||||
setPowerDownState(PowerDownState::Awake, bank);
|
||||
} else if (isInPowerDown(bank)) {
|
||||
// Request wake up from power down. A Power Down Exit request will be generated (PDNAX, PDNPX, SREFX).
|
||||
Command pdnExitCmd = IPowerDownManager::getWakeUpCommand(powerDownStates[bank]);
|
||||
// Mount the command to be scheduled
|
||||
ScheduledCommand pdnExit(pdnExitCmd, time, getExecutionTime(pdnExitCmd, powerDownPayloads[bank]), DramExtension::getExtension(powerDownPayloads[bank]));
|
||||
ScheduledCommand pdnExit(pdnExitCmd, time, getExecutionTime(pdnExitCmd,
|
||||
powerDownPayloads[bank]), DramExtension::getExtension(powerDownPayloads[bank]));
|
||||
// Ensure that time constraints are respected
|
||||
controllerCore.getCommandChecker(pdnExitCmd).delayToSatisfyConstraints(pdnExit);
|
||||
|
||||
if (pdnExitCmd == Command::SREFX) {
|
||||
// Leaving Self Refresh. Plan the next refresh.
|
||||
controllerCore.refreshManager->reInitialize(bank, pdnExit.getEnd());
|
||||
printDebugMessage("Waking up. Leaving Self Refresh on Bank " + to_string(bank.ID()) + " at " + time.to_string() + " next refresh planned to " + pdnExit.getEnd().to_string());
|
||||
printDebugMessage("Waking up. Leaving Self Refresh on Bank " + to_string(
|
||||
bank.ID()) + " at " + time.to_string() + " next refresh planned to " +
|
||||
pdnExit.getEnd().to_string());
|
||||
}
|
||||
|
||||
setPowerDownState(PowerDownState::Awake, bank);
|
||||
|
||||
printDebugMessage("Sending power down exit command " + commandToString(pdnExitCmd) + " on bank " + to_string(bank.ID()) + " at " + time.to_string() + " start time " + pdnExit.getStart().to_string() + " end time " + pdnExit.getEnd().to_string());
|
||||
printDebugMessage("Sending power down exit command " + commandToString(
|
||||
pdnExitCmd) + " on bank " + to_string(bank.ID()) + " at " + time.to_string() +
|
||||
" start time " + pdnExit.getStart().to_string() + " end time " +
|
||||
pdnExit.getEnd().to_string());
|
||||
sendPowerDownPayload(pdnExit);
|
||||
}
|
||||
|
||||
printDebugMessage("Awaken on bank " + to_string(bank.ID()) + " at " + time.to_string() + " current power down state is " + powerDownStateToString(powerDownStates[bank]));
|
||||
printDebugMessage("Awaken on bank " + to_string(bank.ID()) + " at " +
|
||||
time.to_string() + " current power down state is " + powerDownStateToString(
|
||||
powerDownStates[bank]));
|
||||
}
|
||||
|
||||
void PowerDownManagerBankwise::wakeUpForRefresh(Bank bank, sc_time time)
|
||||
{
|
||||
printDebugMessage("Waking up for refresh on bank " + to_string(bank.ID()) + " at " + time.to_string() + " current power down state is " + powerDownStateToString(powerDownStates[bank]));
|
||||
printDebugMessage("Waking up for refresh on bank " + to_string(
|
||||
bank.ID()) + " at " + time.to_string() + " current power down state is " +
|
||||
powerDownStateToString(powerDownStates[bank]));
|
||||
|
||||
if (isInPowerDown(bank)) {
|
||||
// A Power Down Exit request will be generated (PDNAX, PDNPX, SREFX).
|
||||
@@ -132,15 +142,21 @@ void PowerDownManagerBankwise::wakeUpForRefresh(Bank bank, sc_time time)
|
||||
// Get the execution time for this request
|
||||
sc_time executionTime = getExecutionTime(pdnExitCmd, powerDownPayloads[bank]);
|
||||
// Mount the command to be scheduled
|
||||
ScheduledCommand pdnExit(pdnExitCmd, time, executionTime, DramExtension::getExtension(powerDownPayloads[bank]));
|
||||
ScheduledCommand pdnExit(pdnExitCmd, time, executionTime,
|
||||
DramExtension::getExtension(powerDownPayloads[bank]));
|
||||
|
||||
setPowerDownState(PowerDownState::AwakeForRefresh, bank);
|
||||
|
||||
printDebugMessage("Sending power down exit command " + commandToString(pdnExitCmd) + " on bank " + to_string(bank.ID()) + " at " + time.to_string() + " start time " + pdnExit.getStart().to_string() + " end time " + pdnExit.getEnd().to_string());
|
||||
printDebugMessage("Sending power down exit command " + commandToString(
|
||||
pdnExitCmd) + " on bank " + to_string(bank.ID()) + " at " + time.to_string() +
|
||||
" start time " + pdnExit.getStart().to_string() + " end time " +
|
||||
pdnExit.getEnd().to_string());
|
||||
sendPowerDownPayload(pdnExit);
|
||||
}
|
||||
|
||||
printDebugMessage("Awaken for refresh on bank " + to_string(bank.ID()) + " at " + time.to_string() + " current power down state is " + powerDownStateToString(powerDownStates[bank]));
|
||||
printDebugMessage("Awaken for refresh on bank " + to_string(
|
||||
bank.ID()) + " at " + time.to_string() + " current power down state is " +
|
||||
powerDownStateToString(powerDownStates[bank]));
|
||||
}
|
||||
|
||||
bool PowerDownManagerBankwise::isInPowerDown(Bank bank)
|
||||
@@ -163,18 +179,22 @@ bool PowerDownManagerBankwise::isAwake(Bank bank)
|
||||
return powerDownStates[bank] == PowerDownState::Awake;
|
||||
}
|
||||
|
||||
void PowerDownManagerBankwise::setPowerDownState(PowerDownState state, Bank bank)
|
||||
void PowerDownManagerBankwise::setPowerDownState(PowerDownState state,
|
||||
Bank bank)
|
||||
{
|
||||
PowerDownState& bankstate = powerDownStates[bank];
|
||||
PowerDownState &bankstate = powerDownStates[bank];
|
||||
bankstate = state;
|
||||
printDebugMessage("Is now in state " + powerDownStateToString(state) + " on Bank " + to_string(bank.ID()));
|
||||
printDebugMessage("Is now in state " + powerDownStateToString(
|
||||
state) + " on Bank " + to_string(bank.ID()));
|
||||
}
|
||||
|
||||
void PowerDownManagerBankwise::sendPowerDownPayload(ScheduledCommand &pdn)
|
||||
{
|
||||
controllerCore.state->bus.moveCommandToNextFreeSlot(pdn);
|
||||
controllerCore.state->change(pdn);
|
||||
printDebugMessage("Sending power down command " + commandToString(pdn.getCommand()) + " on bank " + to_string(pdn.getBank().ID()) + " start time " + pdn.getStart().to_string() + " end time " + pdn.getEnd().to_string());
|
||||
printDebugMessage("Sending power down command " + commandToString(
|
||||
pdn.getCommand()) + " on bank " + to_string(pdn.getBank().ID()) + " start time "
|
||||
+ pdn.getStart().to_string() + " end time " + pdn.getEnd().to_string());
|
||||
controllerCore.controller.send(pdn, powerDownPayloads[pdn.getBank()]);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,8 +52,9 @@ class ControllerCore;
|
||||
class PowerDownManagerBankwise : public sc_module, public IPowerDownManager
|
||||
{
|
||||
public:
|
||||
PowerDownManagerBankwise(sc_module_name /*name*/, ControllerCore& controllerCore);
|
||||
virtual ~PowerDownManagerBankwise(){}
|
||||
PowerDownManagerBankwise(sc_module_name /*name*/,
|
||||
ControllerCore &controllerCore);
|
||||
virtual ~PowerDownManagerBankwise() {}
|
||||
virtual void triggerSleep(Bank bank, sc_time time) override;
|
||||
virtual void sleep(Bank bank, sc_time time) override;
|
||||
virtual void wakeUp(Bank bank, sc_time time) override;
|
||||
|
||||
@@ -44,7 +44,8 @@
|
||||
|
||||
using namespace tlm;
|
||||
|
||||
PowerDownManagerTimeout::PowerDownManagerTimeout(sc_module_name name, ControllerCore& controllerCore):
|
||||
PowerDownManagerTimeout::PowerDownManagerTimeout(sc_module_name name,
|
||||
ControllerCore &controllerCore):
|
||||
PowerDownManager(name, controllerCore)
|
||||
{
|
||||
//controllerCore.controller.send(PDNTrigger, Configuration::getInstance().getPowerDownTimeout(), powerDownPayloads[Bank(0)]);
|
||||
@@ -58,56 +59,51 @@ PowerDownManagerTimeout::~PowerDownManagerTimeout()
|
||||
void PowerDownManagerTimeout::sleep(Bank /*bank*/, sc_time time)
|
||||
{
|
||||
bool timeoutTest;
|
||||
if(!isAwakeForRefresh())
|
||||
{
|
||||
if (!isAwakeForRefresh()) {
|
||||
sc_time lastReadScheduled;
|
||||
sc_time lastWriteScheduled;
|
||||
if(Configuration::getInstance().OpenPagePolicy)
|
||||
{
|
||||
lastReadScheduled= controllerCore.state->getLastCommand(Command::Read).getEnd();
|
||||
lastWriteScheduled = controllerCore.state->getLastCommand(Command::Write).getEnd();
|
||||
if (Configuration::getInstance().OpenPagePolicy) {
|
||||
lastReadScheduled = controllerCore.state->getLastCommand(
|
||||
Command::Read).getEnd();
|
||||
lastWriteScheduled = controllerCore.state->getLastCommand(
|
||||
Command::Write).getEnd();
|
||||
} else {
|
||||
lastReadScheduled = controllerCore.state->getLastCommand(
|
||||
Command::ReadA).getEnd();
|
||||
lastWriteScheduled = controllerCore.state->getLastCommand(
|
||||
Command::WriteA).getEnd();
|
||||
}
|
||||
else
|
||||
{
|
||||
lastReadScheduled = controllerCore.state->getLastCommand(Command::ReadA).getEnd();
|
||||
lastWriteScheduled = controllerCore.state->getLastCommand(Command::WriteA).getEnd();
|
||||
}
|
||||
sc_time lastScheduledCommand = max(lastReadScheduled,lastWriteScheduled);
|
||||
timeoutTest = (time - lastScheduledCommand) >= Configuration::getInstance().getPowerDownTimeout();
|
||||
}
|
||||
else
|
||||
{
|
||||
sc_time lastScheduledCommand = max(lastReadScheduled, lastWriteScheduled);
|
||||
timeoutTest = (time - lastScheduledCommand) >=
|
||||
Configuration::getInstance().getPowerDownTimeout();
|
||||
} else {
|
||||
timeoutTest = true;
|
||||
}
|
||||
|
||||
//test_awakeForRefresh = false;
|
||||
|
||||
if( canSleep() && !isInPowerDown() && timeoutTest)
|
||||
{
|
||||
if ( canSleep() && !isInPowerDown() && timeoutTest) {
|
||||
|
||||
PowerDownState newState;
|
||||
if(Configuration::getInstance().PowerDownMode == EPowerDownMode::TimeoutPDN)
|
||||
{
|
||||
newState = controllerCore.state->rowBufferStates->allRowBuffersAreClosed() ? PowerDownState::PDNPrecharge : PowerDownState::PDNActive;
|
||||
}
|
||||
else // PowerDownMode == TimeoutSREF
|
||||
{
|
||||
if(!controllerCore.state->rowBufferStates->allRowBuffersAreClosed())
|
||||
{
|
||||
ScheduledCommand prechargeAllMaster(Command::PrechargeAll, time, getExecutionTime(Command::PrechargeAll, powerDownPayloads[Bank(0)]), DramExtension::getExtension(powerDownPayloads[Bank(0)]));
|
||||
if (Configuration::getInstance().PowerDownMode == EPowerDownMode::TimeoutPDN) {
|
||||
newState = controllerCore.state->rowBufferStates->allRowBuffersAreClosed() ?
|
||||
PowerDownState::PDNPrecharge : PowerDownState::PDNActive;
|
||||
} else { // PowerDownMode == TimeoutSREF
|
||||
if (!controllerCore.state->rowBufferStates->allRowBuffersAreClosed()) {
|
||||
ScheduledCommand prechargeAllMaster(Command::PrechargeAll, time,
|
||||
getExecutionTime(Command::PrechargeAll, powerDownPayloads[Bank(0)]),
|
||||
DramExtension::getExtension(powerDownPayloads[Bank(0)]));
|
||||
|
||||
controllerCore.getCommandChecker(Command::PrechargeAll).delayToSatisfyConstraints(prechargeAllMaster);
|
||||
controllerCore.getCommandChecker(
|
||||
Command::PrechargeAll).delayToSatisfyConstraints(prechargeAllMaster);
|
||||
|
||||
if (controllerCore.refreshManager->hasCollision(prechargeAllMaster))
|
||||
{
|
||||
if (controllerCore.refreshManager->hasCollision(prechargeAllMaster)) {
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = 1; i < controllerCore.getBanks().size(); i++)
|
||||
{
|
||||
ScheduledCommand prechargeAll(Command::PrechargeAll, prechargeAllMaster.getStart(), prechargeAllMaster.getExecutionTime(),
|
||||
powerDownPayloads[Bank(i)]);
|
||||
} else {
|
||||
for (size_t i = 1; i < controllerCore.getBanks().size(); i++) {
|
||||
ScheduledCommand prechargeAll(Command::PrechargeAll,
|
||||
prechargeAllMaster.getStart(), prechargeAllMaster.getExecutionTime(),
|
||||
powerDownPayloads[Bank(i)]);
|
||||
controllerCore.state->change(prechargeAll);
|
||||
}
|
||||
controllerCore.state->change(prechargeAllMaster);
|
||||
@@ -125,12 +121,9 @@ void PowerDownManagerTimeout::sleep(Bank /*bank*/, sc_time time)
|
||||
|
||||
controllerCore.getCommandChecker(cmd).delayToSatisfyConstraints(pdn);
|
||||
|
||||
if (controllerCore.refreshManager->hasCollision(pdn))
|
||||
{
|
||||
if (controllerCore.refreshManager->hasCollision(pdn)) {
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
setPowerDownState(newState);
|
||||
sendPowerDownPayload(pdn);
|
||||
}
|
||||
@@ -139,9 +132,9 @@ void PowerDownManagerTimeout::sleep(Bank /*bank*/, sc_time time)
|
||||
|
||||
void PowerDownManagerTimeout::triggerSleep(Bank /*bank*/, sc_time time)
|
||||
{
|
||||
if(canSleep() && !isInPowerDown())
|
||||
{
|
||||
controllerCore.controller.send(PDNTrigger, time + controllerCore.config.getPowerDownTimeout(), powerDownPayloads[Bank(0)]);
|
||||
if (canSleep() && !isInPowerDown()) {
|
||||
controllerCore.controller.send(PDNTrigger,
|
||||
time + controllerCore.config.getPowerDownTimeout(), powerDownPayloads[Bank(0)]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,8 @@ class ControllerCore;
|
||||
class PowerDownManagerTimeout: public PowerDownManager
|
||||
{
|
||||
public:
|
||||
PowerDownManagerTimeout(sc_module_name /*name*/, ControllerCore& controllerCore);
|
||||
PowerDownManagerTimeout(sc_module_name /*name*/,
|
||||
ControllerCore &controllerCore);
|
||||
virtual ~PowerDownManagerTimeout();
|
||||
|
||||
virtual void triggerSleep(Bank /*bank*/, sc_time time);
|
||||
|
||||
@@ -44,7 +44,8 @@
|
||||
|
||||
using namespace tlm;
|
||||
|
||||
PowerDownManagerTimeoutBankwise::PowerDownManagerTimeoutBankwise(sc_module_name name, ControllerCore& controllerCore):
|
||||
PowerDownManagerTimeoutBankwise::PowerDownManagerTimeoutBankwise(
|
||||
sc_module_name name, ControllerCore &controllerCore):
|
||||
PowerDownManagerBankwise(name, controllerCore)
|
||||
{
|
||||
/*for (Bank bank : controllerCore.getBanks())
|
||||
@@ -61,49 +62,44 @@ PowerDownManagerTimeoutBankwise::~PowerDownManagerTimeoutBankwise()
|
||||
void PowerDownManagerTimeoutBankwise::sleep(Bank bank, sc_time time)
|
||||
{
|
||||
bool timeoutTest;
|
||||
if(!isAwakeForRefresh(bank))
|
||||
{
|
||||
if (!isAwakeForRefresh(bank)) {
|
||||
sc_time lastReadScheduled;
|
||||
sc_time lastWriteScheduled;
|
||||
if(Configuration::getInstance().OpenPagePolicy)
|
||||
{
|
||||
lastReadScheduled= controllerCore.state->getLastCommand(Command::Read, bank).getEnd();
|
||||
lastWriteScheduled = controllerCore.state->getLastCommand(Command::Write, bank).getEnd();
|
||||
if (Configuration::getInstance().OpenPagePolicy) {
|
||||
lastReadScheduled = controllerCore.state->getLastCommand(Command::Read,
|
||||
bank).getEnd();
|
||||
lastWriteScheduled = controllerCore.state->getLastCommand(Command::Write,
|
||||
bank).getEnd();
|
||||
} else {
|
||||
lastReadScheduled = controllerCore.state->getLastCommand(Command::ReadA,
|
||||
bank).getEnd();
|
||||
lastWriteScheduled = controllerCore.state->getLastCommand(Command::WriteA,
|
||||
bank).getEnd();
|
||||
}
|
||||
else
|
||||
{
|
||||
lastReadScheduled = controllerCore.state->getLastCommand(Command::ReadA, bank).getEnd();
|
||||
lastWriteScheduled = controllerCore.state->getLastCommand(Command::WriteA, bank).getEnd();
|
||||
}
|
||||
sc_time lastScheduledCommand = max(lastReadScheduled,lastWriteScheduled);
|
||||
timeoutTest = (time - lastScheduledCommand) >= Configuration::getInstance().getPowerDownTimeout();
|
||||
}
|
||||
else
|
||||
{
|
||||
sc_time lastScheduledCommand = max(lastReadScheduled, lastWriteScheduled);
|
||||
timeoutTest = (time - lastScheduledCommand) >=
|
||||
Configuration::getInstance().getPowerDownTimeout();
|
||||
} else {
|
||||
timeoutTest = true;
|
||||
}
|
||||
|
||||
if( canSleep(bank) && !isInPowerDown(bank) && timeoutTest)
|
||||
{
|
||||
if ( canSleep(bank) && !isInPowerDown(bank) && timeoutTest) {
|
||||
PowerDownState newState;
|
||||
if(Configuration::getInstance().PowerDownMode == EPowerDownMode::TimeoutPDN)
|
||||
{
|
||||
newState = controllerCore.state->rowBufferStates->rowBufferIsOpen(bank) ? PowerDownState::PDNActive : PowerDownState::PDNPrecharge;
|
||||
}
|
||||
else // PowerDownMode == TimeoutSREF
|
||||
{
|
||||
if(controllerCore.state->rowBufferStates->rowBufferIsOpen(bank))
|
||||
{
|
||||
ScheduledCommand precharge(Command::Precharge, time, getExecutionTime(Command::Precharge, powerDownPayloads[bank]), DramExtension::getExtension(powerDownPayloads[bank]));
|
||||
if (Configuration::getInstance().PowerDownMode == EPowerDownMode::TimeoutPDN) {
|
||||
newState = controllerCore.state->rowBufferStates->rowBufferIsOpen(
|
||||
bank) ? PowerDownState::PDNActive : PowerDownState::PDNPrecharge;
|
||||
} else { // PowerDownMode == TimeoutSREF
|
||||
if (controllerCore.state->rowBufferStates->rowBufferIsOpen(bank)) {
|
||||
ScheduledCommand precharge(Command::Precharge, time,
|
||||
getExecutionTime(Command::Precharge, powerDownPayloads[bank]),
|
||||
DramExtension::getExtension(powerDownPayloads[bank]));
|
||||
|
||||
controllerCore.getCommandChecker(Command::Precharge).delayToSatisfyConstraints(precharge);
|
||||
controllerCore.getCommandChecker(Command::Precharge).delayToSatisfyConstraints(
|
||||
precharge);
|
||||
|
||||
if (controllerCore.refreshManager->hasCollision(precharge))
|
||||
{
|
||||
if (controllerCore.refreshManager->hasCollision(precharge)) {
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
controllerCore.state->change(precharge);
|
||||
controllerCore.controller.send(precharge, powerDownPayloads[bank]);
|
||||
}
|
||||
@@ -120,12 +116,9 @@ void PowerDownManagerTimeoutBankwise::sleep(Bank bank, sc_time time)
|
||||
|
||||
controllerCore.getCommandChecker(cmd).delayToSatisfyConstraints(pdn);
|
||||
|
||||
if (controllerCore.refreshManager->hasCollision(pdn))
|
||||
{
|
||||
if (controllerCore.refreshManager->hasCollision(pdn)) {
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
setPowerDownState(newState, bank);
|
||||
sendPowerDownPayload(pdn);
|
||||
}
|
||||
@@ -134,8 +127,8 @@ void PowerDownManagerTimeoutBankwise::sleep(Bank bank, sc_time time)
|
||||
|
||||
void PowerDownManagerTimeoutBankwise::triggerSleep(Bank bank, sc_time time)
|
||||
{
|
||||
if(canSleep(bank) && !isInPowerDown(bank))
|
||||
{
|
||||
controllerCore.controller.send(PDNTrigger, time + controllerCore.config.getPowerDownTimeout(), powerDownPayloads[bank]);
|
||||
if (canSleep(bank) && !isInPowerDown(bank)) {
|
||||
controllerCore.controller.send(PDNTrigger,
|
||||
time + controllerCore.config.getPowerDownTimeout(), powerDownPayloads[bank]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,8 @@ class ControllerCore;
|
||||
class PowerDownManagerTimeoutBankwise: public PowerDownManagerBankwise
|
||||
{
|
||||
public:
|
||||
PowerDownManagerTimeoutBankwise(sc_module_name /*name*/, ControllerCore& controllerCore);
|
||||
PowerDownManagerTimeoutBankwise(sc_module_name /*name*/,
|
||||
ControllerCore &controllerCore);
|
||||
virtual ~PowerDownManagerTimeoutBankwise();
|
||||
|
||||
virtual void triggerSleep(Bank bank, sc_time time);
|
||||
|
||||
@@ -45,13 +45,14 @@
|
||||
class IRefreshManager
|
||||
{
|
||||
public:
|
||||
virtual ~IRefreshManager(){};
|
||||
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;
|
||||
virtual ~IRefreshManager() {};
|
||||
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;
|
||||
|
||||
|
||||
virtual bool isInvalidated(tlm::tlm_generic_payload& payload, sc_time time) = 0;
|
||||
virtual bool isInvalidated(tlm::tlm_generic_payload &payload, sc_time time) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -44,19 +44,19 @@
|
||||
|
||||
using namespace tlm;
|
||||
|
||||
RefreshManager::RefreshManager(sc_module_name /*name*/, ControllerCore& controller) :
|
||||
controllerCore(controller), timing(controller.config.memSpec.refreshTimings[Bank(0)]), nextPlannedRefresh(SC_ZERO_TIME)
|
||||
RefreshManager::RefreshManager(sc_module_name /*name*/,
|
||||
ControllerCore &controller) :
|
||||
controllerCore(controller),
|
||||
timing(controller.config.memSpec.refreshTimings[Bank(0)]),
|
||||
nextPlannedRefresh(SC_ZERO_TIME)
|
||||
{
|
||||
if (controllerCore.config.ControllerCoreEnableRefPostpone)
|
||||
{
|
||||
if (controllerCore.config.ControllerCoreEnableRefPostpone) {
|
||||
maxpostpone = controllerCore.config.ControllerCoreMaxPostponedARCmd;
|
||||
}
|
||||
if (controllerCore.config.ControllerCoreEnableRefPullIn)
|
||||
{
|
||||
if (controllerCore.config.ControllerCoreEnableRefPullIn) {
|
||||
maxpullin = controllerCore.config.ControllerCoreMaxPulledInARCmd;
|
||||
}
|
||||
for (Bank bank : controller.getBanks())
|
||||
{
|
||||
for (Bank bank : controller.getBanks()) {
|
||||
setUpDummy(refreshPayloads[bank], bank);
|
||||
}
|
||||
planNextRefresh(timing.tREFI);
|
||||
@@ -67,33 +67,38 @@ RefreshManager::~RefreshManager()
|
||||
}
|
||||
|
||||
//Check if a command will be scheduled during the next refresh period
|
||||
bool RefreshManager::hasCollision(const ScheduledCommand& command)
|
||||
bool RefreshManager::hasCollision(const ScheduledCommand &command)
|
||||
{
|
||||
bool collisionWithPreviousRefEnd = command.getStart() < controllerCore.state->getLastCommand(Command::AutoRefresh).getEnd();
|
||||
bool collisionWithPreviousRefEnd = command.getStart() <
|
||||
controllerCore.state->getLastCommand(Command::AutoRefresh).getEnd();
|
||||
bool collisionWithNextRefStart = command.getEnd() >= nextPlannedRefresh;
|
||||
|
||||
if (controllerCore.config.ControllerCoreEnableRefPostpone && (arCmdCounter < maxpostpone)) // Flexible refresh is on and have "credits" to postpone
|
||||
{
|
||||
collisionWithNextRefStart = false; // Then there will not be a collision with next refresh because nextPlannedRefresh will be updated
|
||||
if (controllerCore.config.ControllerCoreEnableRefPostpone
|
||||
&& (arCmdCounter <
|
||||
maxpostpone)) { // Flexible refresh is on and have "credits" to postpone
|
||||
collisionWithNextRefStart =
|
||||
false; // Then there will not be a collision with next refresh because nextPlannedRefresh will be updated
|
||||
}
|
||||
return collisionWithPreviousRefEnd || collisionWithNextRefStart;
|
||||
}
|
||||
|
||||
void RefreshManager::doRefresh(tlm::tlm_generic_payload& payload __attribute__((unused)), sc_time time)
|
||||
void RefreshManager::doRefresh(tlm::tlm_generic_payload &payload __attribute__((
|
||||
unused)), sc_time time)
|
||||
{
|
||||
sc_assert(!isInvalidated(payload, time));
|
||||
|
||||
//Check if any row on all banks is activated and if so, a PrechargeAll command must be scheduled before the refresh command.
|
||||
if (!controllerCore.state->rowBufferStates->allRowBuffersAreClosed())
|
||||
{
|
||||
ScheduledCommand prechargeAllMaster(Command::PrechargeAll, time, getExecutionTime(Command::PrechargeAll, refreshPayloads[Bank(0)]),
|
||||
refreshPayloads[Bank(0)]);
|
||||
controllerCore.getCommandChecker(Command::PrechargeAll).delayToSatisfyConstraints(prechargeAllMaster);
|
||||
if (!controllerCore.state->rowBufferStates->allRowBuffersAreClosed()) {
|
||||
ScheduledCommand prechargeAllMaster(Command::PrechargeAll, time,
|
||||
getExecutionTime(Command::PrechargeAll, refreshPayloads[Bank(0)]),
|
||||
refreshPayloads[Bank(0)]);
|
||||
controllerCore.getCommandChecker(
|
||||
Command::PrechargeAll).delayToSatisfyConstraints(prechargeAllMaster);
|
||||
|
||||
for (size_t i = 1;i < controllerCore.getBanks().size(); i++)
|
||||
{
|
||||
ScheduledCommand prechargeAll(Command::PrechargeAll, prechargeAllMaster.getStart(), prechargeAllMaster.getExecutionTime(),
|
||||
refreshPayloads[Bank(i)]);
|
||||
for (size_t i = 1; i < controllerCore.getBanks().size(); i++) {
|
||||
ScheduledCommand prechargeAll(Command::PrechargeAll,
|
||||
prechargeAllMaster.getStart(), prechargeAllMaster.getExecutionTime(),
|
||||
refreshPayloads[Bank(i)]);
|
||||
controllerCore.state->change(prechargeAll);
|
||||
}
|
||||
controllerCore.state->change(prechargeAllMaster);
|
||||
@@ -101,13 +106,15 @@ void RefreshManager::doRefresh(tlm::tlm_generic_payload& payload __attribute__((
|
||||
}
|
||||
|
||||
//Otherwise just the AutoRefresh command is scheduled.
|
||||
ScheduledCommand refreshAllMaster(Command::AutoRefresh, time, getExecutionTime(Command::AutoRefresh, refreshPayloads[Bank(0)]),
|
||||
DramExtension::getExtension(refreshPayloads[Bank(0)]));
|
||||
controllerCore.getCommandChecker(Command::AutoRefresh).delayToSatisfyConstraints(refreshAllMaster);
|
||||
ScheduledCommand refreshAllMaster(Command::AutoRefresh, time,
|
||||
getExecutionTime(Command::AutoRefresh, refreshPayloads[Bank(0)]),
|
||||
DramExtension::getExtension(refreshPayloads[Bank(0)]));
|
||||
controllerCore.getCommandChecker(
|
||||
Command::AutoRefresh).delayToSatisfyConstraints(refreshAllMaster);
|
||||
|
||||
for (size_t i = 1;i < controllerCore.getBanks().size(); i++)
|
||||
{
|
||||
ScheduledCommand refresh(Command::AutoRefresh, refreshAllMaster.getStart(), refreshAllMaster.getExecutionTime(),refreshPayloads[Bank(i)]);
|
||||
for (size_t i = 1; i < controllerCore.getBanks().size(); i++) {
|
||||
ScheduledCommand refresh(Command::AutoRefresh, refreshAllMaster.getStart(),
|
||||
refreshAllMaster.getExecutionTime(), refreshPayloads[Bank(i)]);
|
||||
controllerCore.state->change(refresh);
|
||||
DramExtension::getExtension(refreshPayloads[Bank(i)]).incrementRow();
|
||||
}
|
||||
@@ -117,7 +124,8 @@ void RefreshManager::doRefresh(tlm::tlm_generic_payload& payload __attribute__((
|
||||
}
|
||||
|
||||
|
||||
void RefreshManager::scheduleRefresh(tlm::tlm_generic_payload& payload __attribute__((unused)), sc_time time)
|
||||
void RefreshManager::scheduleRefresh(tlm::tlm_generic_payload &payload
|
||||
__attribute__((unused)), sc_time time)
|
||||
{
|
||||
sc_time nextRefTiming;
|
||||
bool pendingReq = controllerCore.hasPendingRequests();
|
||||
@@ -127,121 +135,103 @@ void RefreshManager::scheduleRefresh(tlm::tlm_generic_payload& payload __attribu
|
||||
previousState = currentState;
|
||||
currentState = nextState;
|
||||
|
||||
switch(currentState)
|
||||
{
|
||||
case ST_REFRESH:
|
||||
switch (currentState) {
|
||||
case ST_REFRESH:
|
||||
// Regular Refresh. It's possible to migrate from this to the flexible refresh states
|
||||
|
||||
assert(arCmdCounter == 0); // The arCmdCounter should always be equal to zero here
|
||||
assert(arCmdCounter ==
|
||||
0); // The arCmdCounter should always be equal to zero here
|
||||
|
||||
if(canPostpone)
|
||||
{
|
||||
nextState = ST_POSTPONE;
|
||||
nextRefTiming = SC_ZERO_TIME;
|
||||
}
|
||||
else if(canPullIn)
|
||||
{
|
||||
nextState = ST_PULLIN;
|
||||
nextRefTiming = SC_ZERO_TIME; // Attempt to burst pull-in
|
||||
}
|
||||
else
|
||||
{
|
||||
doRefresh(payload, time);
|
||||
nextRefTiming = timing.tREFI;
|
||||
nextState = ST_REFRESH;
|
||||
}
|
||||
break;
|
||||
if (canPostpone) {
|
||||
nextState = ST_POSTPONE;
|
||||
nextRefTiming = SC_ZERO_TIME;
|
||||
} else if (canPullIn) {
|
||||
nextState = ST_PULLIN;
|
||||
nextRefTiming = SC_ZERO_TIME; // Attempt to burst pull-in
|
||||
} else {
|
||||
doRefresh(payload, time);
|
||||
nextRefTiming = timing.tREFI;
|
||||
nextState = ST_REFRESH;
|
||||
}
|
||||
break;
|
||||
|
||||
case ST_PULLIN:
|
||||
case ST_PULLIN:
|
||||
// Pull-In Refresh. Try to pull-in refreshes as long as the limit hasn't been reached yet and has credits
|
||||
|
||||
if(canPullIn)
|
||||
{
|
||||
doRefresh(payload, time);
|
||||
arCmdCounter++;
|
||||
nextState = ST_PULLIN;
|
||||
nextRefTiming = timing.tRFC;
|
||||
}
|
||||
else
|
||||
{
|
||||
alignValue = arCmdCounter; // Saving value to be used by ST_ALIGN
|
||||
nextState = ST_ALIGN;
|
||||
nextRefTiming = SC_ZERO_TIME;
|
||||
}
|
||||
break;
|
||||
if (canPullIn) {
|
||||
doRefresh(payload, time);
|
||||
arCmdCounter++;
|
||||
nextState = ST_PULLIN;
|
||||
nextRefTiming = timing.tRFC;
|
||||
} else {
|
||||
alignValue = arCmdCounter; // Saving value to be used by ST_ALIGN
|
||||
nextState = ST_ALIGN;
|
||||
nextRefTiming = SC_ZERO_TIME;
|
||||
}
|
||||
break;
|
||||
|
||||
case ST_SKIP:
|
||||
case ST_SKIP:
|
||||
// Skip Refresh. The arCmdCounter is used to skip the correct amount of refreshes
|
||||
|
||||
arCmdCounter--;
|
||||
if(arCmdCounter == 0)
|
||||
{
|
||||
nextState = ST_REFRESH;
|
||||
nextRefTiming = SC_ZERO_TIME;
|
||||
}
|
||||
else
|
||||
{
|
||||
nextState = ST_SKIP;
|
||||
nextRefTiming = timing.tREFI;
|
||||
}
|
||||
break;
|
||||
arCmdCounter--;
|
||||
if (arCmdCounter == 0) {
|
||||
nextState = ST_REFRESH;
|
||||
nextRefTiming = SC_ZERO_TIME;
|
||||
} else {
|
||||
nextState = ST_SKIP;
|
||||
nextRefTiming = timing.tREFI;
|
||||
}
|
||||
break;
|
||||
|
||||
case ST_POSTPONE:
|
||||
case ST_POSTPONE:
|
||||
// Postpone Refresh. Delaying refreshes as long as there are pending requests and credits to postpone. Should be followed by a burst refresh
|
||||
|
||||
if((arCmdCounter == maxpostpone) || ((!pendingReq) && !controllerCore.config.ControllerCoreForceMaxRefBurst)) // Burst conditions met
|
||||
{
|
||||
if(arCmdCounter < maxpostpone) // In case the burst was started by inactivity, need to also count the current REF
|
||||
{
|
||||
arCmdCounter++;
|
||||
}
|
||||
alignValue = arCmdCounter; // Will start a burst next, so the value is saved to be used by ST_ALIGN
|
||||
nextState = ST_BURST;
|
||||
nextRefTiming = SC_ZERO_TIME;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((arCmdCounter == maxpostpone) || ((!pendingReq)
|
||||
&& !controllerCore.config.ControllerCoreForceMaxRefBurst)) { // Burst conditions met
|
||||
if (arCmdCounter <
|
||||
maxpostpone) { // In case the burst was started by inactivity, need to also count the current REF
|
||||
arCmdCounter++;
|
||||
nextState = ST_POSTPONE;
|
||||
nextRefTiming = timing.tREFI;
|
||||
}
|
||||
break;
|
||||
alignValue =
|
||||
arCmdCounter; // Will start a burst next, so the value is saved to be used by ST_ALIGN
|
||||
nextState = ST_BURST;
|
||||
nextRefTiming = SC_ZERO_TIME;
|
||||
} else {
|
||||
arCmdCounter++;
|
||||
nextState = ST_POSTPONE;
|
||||
nextRefTiming = timing.tREFI;
|
||||
}
|
||||
break;
|
||||
|
||||
case ST_BURST:
|
||||
case ST_BURST:
|
||||
// Burst Refresh. The arCmdCounter is used to issue the correct amount of refreshes
|
||||
|
||||
arCmdCounter--;
|
||||
doRefresh(payload, time);
|
||||
if(arCmdCounter == 0) // All bursts issued, next state will align to tREFI
|
||||
{
|
||||
nextState = ST_ALIGN;
|
||||
nextRefTiming = SC_ZERO_TIME;
|
||||
}
|
||||
else
|
||||
{
|
||||
nextState = ST_BURST;
|
||||
nextRefTiming = timing.tRFC;
|
||||
}
|
||||
break;
|
||||
arCmdCounter--;
|
||||
doRefresh(payload, time);
|
||||
if (arCmdCounter == 0) { // All bursts issued, next state will align to tREFI
|
||||
nextState = ST_ALIGN;
|
||||
nextRefTiming = SC_ZERO_TIME;
|
||||
} else {
|
||||
nextState = ST_BURST;
|
||||
nextRefTiming = timing.tRFC;
|
||||
}
|
||||
break;
|
||||
|
||||
case ST_ALIGN:
|
||||
case ST_ALIGN:
|
||||
// Align Refresh. Adjusting the timing so the next REF timing will be a in a time multiple of tREFI
|
||||
|
||||
if(previousState == ST_PULLIN)
|
||||
{
|
||||
nextRefTiming = timing.tREFI-(timing.tRFC*(alignValue));
|
||||
nextState = ST_SKIP;
|
||||
}
|
||||
else
|
||||
{
|
||||
nextRefTiming = timing.tREFI-(timing.tRFC*(alignValue-1));
|
||||
nextState = ST_REFRESH;
|
||||
}
|
||||
break;
|
||||
if (previousState == ST_PULLIN) {
|
||||
nextRefTiming = timing.tREFI - (timing.tRFC * (alignValue));
|
||||
nextState = ST_SKIP;
|
||||
} else {
|
||||
nextRefTiming = timing.tREFI - (timing.tRFC * (alignValue - 1));
|
||||
nextState = ST_REFRESH;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
SC_REPORT_FATAL(this->name(),"Invalid State in Flexible Refresh FSM. Stop.");
|
||||
break;
|
||||
default:
|
||||
SC_REPORT_FATAL(this->name(), "Invalid State in Flexible Refresh FSM. Stop.");
|
||||
break;
|
||||
}
|
||||
|
||||
planNextRefresh(nextRefTiming);
|
||||
@@ -250,7 +240,8 @@ void RefreshManager::scheduleRefresh(tlm::tlm_generic_payload& payload __attribu
|
||||
void RefreshManager::planNextRefresh(sc_time nextRefTiming)
|
||||
{
|
||||
nextPlannedRefresh += nextRefTiming;
|
||||
controllerCore.controller.send(REFTrigger, nextPlannedRefresh, refreshPayloads[Bank(0)]);
|
||||
controllerCore.controller.send(REFTrigger, nextPlannedRefresh,
|
||||
refreshPayloads[Bank(0)]);
|
||||
}
|
||||
|
||||
void RefreshManager::reInitialize(Bank /*bank*/, sc_time time)
|
||||
@@ -259,7 +250,8 @@ void RefreshManager::reInitialize(Bank /*bank*/, sc_time time)
|
||||
planNextRefresh(timing.tREFI);
|
||||
}
|
||||
|
||||
bool RefreshManager::isInvalidated(tlm::tlm_generic_payload& payload __attribute__((unused)), sc_time time)
|
||||
bool RefreshManager::isInvalidated(tlm::tlm_generic_payload &payload
|
||||
__attribute__((unused)), sc_time time)
|
||||
{
|
||||
return nextPlannedRefresh > time;
|
||||
}
|
||||
|
||||
@@ -40,8 +40,7 @@
|
||||
#include "IRefreshManager.h"
|
||||
#include "../configuration/MemSpec.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
typedef enum {
|
||||
ST_REFRESH = 0,
|
||||
ST_PULLIN,
|
||||
ST_POSTPONE,
|
||||
@@ -55,17 +54,19 @@ class ControllerCore;
|
||||
class RefreshManager : public IRefreshManager, public sc_module
|
||||
{
|
||||
public:
|
||||
RefreshManager(sc_module_name /*name*/, ControllerCore& controllerCore);
|
||||
RefreshManager(sc_module_name /*name*/, ControllerCore &controllerCore);
|
||||
virtual ~RefreshManager();
|
||||
|
||||
virtual bool hasCollision(const ScheduledCommand& command) override;
|
||||
virtual void scheduleRefresh(tlm::tlm_generic_payload& payload, sc_time time) 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;
|
||||
virtual bool isInvalidated(tlm::tlm_generic_payload &payload,
|
||||
sc_time time) override;
|
||||
|
||||
private:
|
||||
ControllerCore& controllerCore;
|
||||
RefreshTiming& timing;
|
||||
ControllerCore &controllerCore;
|
||||
RefreshTiming &timing;
|
||||
sc_time nextPlannedRefresh;
|
||||
std::map<Bank, tlm::tlm_generic_payload> refreshPayloads;
|
||||
unsigned int maxpostpone = 0;
|
||||
@@ -77,7 +78,7 @@ private:
|
||||
ref_fsm_state_t previousState = ST_REFRESH;
|
||||
ref_fsm_state_t nextState = ST_REFRESH;
|
||||
|
||||
void doRefresh(tlm::tlm_generic_payload& payload, sc_time time);
|
||||
void doRefresh(tlm::tlm_generic_payload &payload, sc_time time);
|
||||
void planNextRefresh(sc_time time);
|
||||
void printDebugMessage(std::string message);
|
||||
};
|
||||
|
||||
@@ -42,10 +42,10 @@
|
||||
using namespace std;
|
||||
|
||||
|
||||
RefreshManagerBankwise::RefreshManagerBankwise(sc_module_name /*name*/, ControllerCore& controller) : controllerCore(controller)
|
||||
RefreshManagerBankwise::RefreshManagerBankwise(sc_module_name /*name*/,
|
||||
ControllerCore &controller) : controllerCore(controller)
|
||||
{
|
||||
for (Bank bank : controller.getBanks())
|
||||
{
|
||||
for (Bank bank : controller.getBanks()) {
|
||||
setUpDummy(refreshPayloads[bank], bank);
|
||||
planNextRefresh(bank);
|
||||
}
|
||||
@@ -55,50 +55,60 @@ RefreshManagerBankwise::~RefreshManagerBankwise()
|
||||
{
|
||||
}
|
||||
|
||||
bool RefreshManagerBankwise::hasCollision(const ScheduledCommand& command)
|
||||
bool RefreshManagerBankwise::hasCollision(const ScheduledCommand &command)
|
||||
{
|
||||
Bank bank = command.getBank();
|
||||
// Get the last AutoRefresh command for this bank and the time of its end
|
||||
ScheduledCommand lastAutoRefreshCmd = controllerCore.state->getLastCommand(Command::AutoRefresh, bank);
|
||||
sc_time endTimeLastAutoRefreshCmd = lastAutoRefreshCmd.getEnd();
|
||||
// Get the time of the next planned refresh for this bank
|
||||
sc_time timeNextPlannedRefresh = nextPlannedRefreshs[command.getBank()];
|
||||
// Collision:
|
||||
// - the start time of the command is before the end time of the last auto refresh command for this bank
|
||||
// - the end time of the command is after the next planned refresh for this bank
|
||||
return command.getStart() < endTimeLastAutoRefreshCmd || command.getEnd() > timeNextPlannedRefresh;
|
||||
Bank bank = command.getBank();
|
||||
// Get the last AutoRefresh command for this bank and the time of its end
|
||||
ScheduledCommand lastAutoRefreshCmd = controllerCore.state->getLastCommand(
|
||||
Command::AutoRefresh, bank);
|
||||
sc_time endTimeLastAutoRefreshCmd = lastAutoRefreshCmd.getEnd();
|
||||
// Get the time of the next planned refresh for this bank
|
||||
sc_time timeNextPlannedRefresh = nextPlannedRefreshs[command.getBank()];
|
||||
// Collision:
|
||||
// - the start time of the command is before the end time of the last auto refresh command for this bank
|
||||
// - the end time of the command is after the next planned refresh for this bank
|
||||
return command.getStart() < endTimeLastAutoRefreshCmd
|
||||
|| command.getEnd() > timeNextPlannedRefresh;
|
||||
}
|
||||
|
||||
void RefreshManagerBankwise::scheduleRefresh(tlm::tlm_generic_payload& payload, sc_time time)
|
||||
void RefreshManagerBankwise::scheduleRefresh(tlm::tlm_generic_payload &payload,
|
||||
sc_time time)
|
||||
{
|
||||
sc_assert(!isInvalidated(payload, time));
|
||||
|
||||
tlm::tlm_generic_payload& refreshPayload = refreshPayloads[DramExtension::getExtension(payload).getBank()];
|
||||
tlm::tlm_generic_payload &refreshPayload =
|
||||
refreshPayloads[DramExtension::getExtension(payload).getBank()];
|
||||
|
||||
DramExtension& extension = DramExtension::getExtension(refreshPayload);
|
||||
DramExtension &extension = DramExtension::getExtension(refreshPayload);
|
||||
|
||||
if (controllerCore.state->rowBufferStates->rowBufferIsOpen(extension.getBank()))
|
||||
{
|
||||
ScheduledCommand precharge(Command::Precharge, time, getExecutionTime(Command::Precharge, refreshPayload), extension);
|
||||
if (controllerCore.state->rowBufferStates->rowBufferIsOpen(
|
||||
extension.getBank())) {
|
||||
ScheduledCommand precharge(Command::Precharge, time,
|
||||
getExecutionTime(Command::Precharge, refreshPayload), extension);
|
||||
|
||||
controllerCore.getCommandChecker(Command::Precharge).delayToSatisfyConstraints(precharge);
|
||||
controllerCore.getCommandChecker(Command::Precharge).delayToSatisfyConstraints(
|
||||
precharge);
|
||||
controllerCore.state->change(precharge);
|
||||
controllerCore.controller.send(precharge, refreshPayload);
|
||||
}
|
||||
|
||||
ScheduledCommand refresh(Command::AutoRefresh, time, getExecutionTime(Command::AutoRefresh, refreshPayload), extension);
|
||||
controllerCore.getCommandChecker(Command::AutoRefresh).delayToSatisfyConstraints(refresh);
|
||||
ScheduledCommand refresh(Command::AutoRefresh, time,
|
||||
getExecutionTime(Command::AutoRefresh, refreshPayload), extension);
|
||||
controllerCore.getCommandChecker(
|
||||
Command::AutoRefresh).delayToSatisfyConstraints(refresh);
|
||||
controllerCore.state->change(refresh);
|
||||
extension.incrementRow();
|
||||
controllerCore.controller.send(refresh, refreshPayload);
|
||||
|
||||
planNextRefresh(extension.getBank());
|
||||
planNextRefresh(extension.getBank());
|
||||
}
|
||||
|
||||
void RefreshManagerBankwise::planNextRefresh(Bank bank)
|
||||
{
|
||||
nextPlannedRefreshs[bank] += Configuration::getInstance().memSpec.refreshTimings[bank].tREFI;
|
||||
controllerCore.controller.send(REFTrigger, nextPlannedRefreshs[bank], refreshPayloads[bank]);
|
||||
nextPlannedRefreshs[bank] +=
|
||||
Configuration::getInstance().memSpec.refreshTimings[bank].tREFI;
|
||||
controllerCore.controller.send(REFTrigger, nextPlannedRefreshs[bank],
|
||||
refreshPayloads[bank]);
|
||||
}
|
||||
|
||||
void RefreshManagerBankwise::reInitialize(Bank bank, sc_time time)
|
||||
@@ -107,13 +117,15 @@ void RefreshManagerBankwise::reInitialize(Bank bank, sc_time time)
|
||||
planNextRefresh(bank);
|
||||
}
|
||||
|
||||
bool RefreshManagerBankwise::isInvalidated(tlm::tlm_generic_payload& payload, sc_time time)
|
||||
bool RefreshManagerBankwise::isInvalidated(tlm::tlm_generic_payload &payload,
|
||||
sc_time time)
|
||||
{
|
||||
return nextPlannedRefreshs[DramExtension::getExtension(payload).getBank()] > time;
|
||||
return nextPlannedRefreshs[DramExtension::getExtension(payload).getBank()] >
|
||||
time;
|
||||
}
|
||||
|
||||
void RefreshManagerBankwise::printDebugMessage(std::string message)
|
||||
{
|
||||
DebugManager::getInstance().printDebugMessage(this->name(), message);
|
||||
DebugManager::getInstance().printDebugMessage(this->name(), message);
|
||||
}
|
||||
|
||||
|
||||
@@ -47,25 +47,26 @@ class ControllerCore;
|
||||
class RefreshManagerBankwise : public IRefreshManager, public sc_module
|
||||
{
|
||||
public:
|
||||
RefreshManagerBankwise(sc_module_name /*name*/, ControllerCore& controllerCore);
|
||||
virtual ~RefreshManagerBankwise();
|
||||
RefreshManagerBankwise(sc_module_name /*name*/, ControllerCore &controllerCore);
|
||||
virtual ~RefreshManagerBankwise();
|
||||
|
||||
virtual bool hasCollision(const ScheduledCommand& command) override;
|
||||
virtual void scheduleRefresh(tlm::tlm_generic_payload& payload, sc_time time) 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;
|
||||
void reInitialize(Bank bank, sc_time time) override;
|
||||
|
||||
bool isInvalidated(tlm::tlm_generic_payload& payload,sc_time time) override;
|
||||
bool isInvalidated(tlm::tlm_generic_payload &payload, sc_time time) override;
|
||||
|
||||
private:
|
||||
ControllerCore &controllerCore;
|
||||
ControllerCore &controllerCore;
|
||||
|
||||
std::map<Bank, tlm::tlm_generic_payload> refreshPayloads;
|
||||
std::map<Bank, sc_time> nextPlannedRefreshs;
|
||||
std::map<Bank, tlm::tlm_generic_payload> refreshPayloads;
|
||||
std::map<Bank, sc_time> nextPlannedRefreshs;
|
||||
|
||||
void planNextRefresh(Bank bank);
|
||||
void planNextRefresh(Bank bank);
|
||||
|
||||
void printDebugMessage(std::string message);
|
||||
void printDebugMessage(std::string message);
|
||||
};
|
||||
|
||||
#endif /* BANKWISEREFRESHMANAGER_H_ */
|
||||
|
||||
@@ -41,7 +41,8 @@
|
||||
|
||||
bool ScheduledCommand::isNoCommand() const
|
||||
{
|
||||
return (command == Command::NOP && start == SC_ZERO_TIME && executionTime == SC_ZERO_TIME && end == SC_ZERO_TIME);
|
||||
return (command == Command::NOP && start == SC_ZERO_TIME
|
||||
&& executionTime == SC_ZERO_TIME && end == SC_ZERO_TIME);
|
||||
}
|
||||
|
||||
|
||||
@@ -63,12 +64,13 @@ void ScheduledCommand::setStart(sc_time newStart)
|
||||
|
||||
void ScheduledCommand::delayStart(sc_time delay)
|
||||
{
|
||||
setStart(start+delay);
|
||||
setStart(start + delay);
|
||||
}
|
||||
|
||||
// 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)
|
||||
void ScheduledCommand::establishMinDistanceFromStart(sc_time previous,
|
||||
sc_time constraint)
|
||||
{
|
||||
delayStart(getDelayToMeetConstraint(previous, start, constraint));
|
||||
}
|
||||
@@ -108,12 +110,13 @@ unsigned int ScheduledCommand::getBurstLength() const
|
||||
return extension.getBurstlength();
|
||||
}
|
||||
|
||||
bool ScheduledCommand::operator ==(const ScheduledCommand& b) const
|
||||
bool ScheduledCommand::operator ==(const ScheduledCommand &b) const
|
||||
{
|
||||
return b.command == command && b.start == start && b.executionTime == executionTime && b.end == end;
|
||||
return b.command == command && b.start == start
|
||||
&& b.executionTime == executionTime && b.end == end;
|
||||
}
|
||||
|
||||
bool ScheduledCommand::commandIsIn(const std::vector<Command>& commandSet) const
|
||||
bool ScheduledCommand::commandIsIn(const std::vector<Command> &commandSet) const
|
||||
{
|
||||
return isIn(command, commandSet);
|
||||
}
|
||||
@@ -122,17 +125,16 @@ TimeInterval ScheduledCommand::getIntervalOnDataStrobe() const
|
||||
{
|
||||
//only read and write commands have an assoicated time on the data strobe
|
||||
sc_assert(getCommand() == Command::Read || getCommand() == Command::ReadA
|
||||
|| getCommand() == Command::Write
|
||||
|| getCommand() == Command::WriteA);
|
||||
|| getCommand() == Command::Write
|
||||
|| getCommand() == Command::WriteA);
|
||||
|
||||
MemSpec& timings = Configuration::getInstance().memSpec;
|
||||
MemSpec &timings = Configuration::getInstance().memSpec;
|
||||
|
||||
if (getCommand() == Command::Read || getCommand() == Command::ReadA)
|
||||
{
|
||||
return TimeInterval(getStart() + timings.tRL, getStart() + timings.tRL + getReadAccessTime());
|
||||
}
|
||||
else
|
||||
{
|
||||
return TimeInterval(getStart() + timings.tWL - timings.clk / 2, getStart() + timings.tWL + getWriteAccessTime() - timings.clk / 2);
|
||||
if (getCommand() == Command::Read || getCommand() == Command::ReadA) {
|
||||
return TimeInterval(getStart() + timings.tRL,
|
||||
getStart() + timings.tRL + getReadAccessTime());
|
||||
} else {
|
||||
return TimeInterval(getStart() + timings.tWL - timings.clk / 2,
|
||||
getStart() + timings.tWL + getWriteAccessTime() - timings.clk / 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,20 +47,25 @@ class ScheduledCommand
|
||||
{
|
||||
public:
|
||||
|
||||
ScheduledCommand(Command command, sc_time start, sc_time executionTime, const DramExtension& extension) :
|
||||
command(command), start(start), executionTime(executionTime),end(start+executionTime),
|
||||
extension(extension)
|
||||
ScheduledCommand(Command command, sc_time start, sc_time executionTime,
|
||||
const DramExtension &extension) :
|
||||
command(command), start(start), executionTime(executionTime),
|
||||
end(start + executionTime),
|
||||
extension(extension)
|
||||
{
|
||||
}
|
||||
|
||||
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, 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()
|
||||
command(Command::NOP), start(SC_ZERO_TIME), executionTime(SC_ZERO_TIME),
|
||||
end(SC_ZERO_TIME), extension()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -81,8 +86,8 @@ public:
|
||||
Row getRow() const;
|
||||
|
||||
unsigned int getBurstLength() const;
|
||||
bool operator ==(const ScheduledCommand& b) const;
|
||||
bool commandIsIn(const std::vector<Command>& commandSet) const;
|
||||
bool operator ==(const ScheduledCommand &b) const;
|
||||
bool commandIsIn(const std::vector<Command> &commandSet) const;
|
||||
|
||||
TimeInterval getIntervalOnDataStrobe() const;
|
||||
|
||||
|
||||
@@ -45,67 +45,67 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
void ActivateChecker::delayToSatisfyConstraints(ScheduledCommand& command) const
|
||||
void ActivateChecker::delayToSatisfyConstraints(ScheduledCommand &command) const
|
||||
{
|
||||
sc_assert(command.getCommand() == Command::Activate);
|
||||
|
||||
ScheduledCommand lastCommandOnBank = state.getLastScheduledCommand(command.getBank());
|
||||
if (lastCommandOnBank.isValidCommand())
|
||||
{
|
||||
if (lastCommandOnBank.getCommand() == Command::Precharge || lastCommandOnBank.getCommand() == Command::PrechargeAll)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), config.memSpec.tRP);
|
||||
}
|
||||
else if (lastCommandOnBank.getCommand() == Command::ReadA)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), config.memSpec.tRTP + config.memSpec.tRP);
|
||||
}
|
||||
else if (lastCommandOnBank.getCommand() == Command::WriteA)
|
||||
{
|
||||
ScheduledCommand lastCommandOnBank = state.getLastScheduledCommand(
|
||||
command.getBank());
|
||||
if (lastCommandOnBank.isValidCommand()) {
|
||||
if (lastCommandOnBank.getCommand() == Command::Precharge
|
||||
|| lastCommandOnBank.getCommand() == Command::PrechargeAll) {
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(),
|
||||
config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR + config.memSpec.tRP);
|
||||
}
|
||||
else if (lastCommandOnBank.getCommand() == Command::AutoRefresh)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), config.memSpec.tRFC);
|
||||
}
|
||||
else if (lastCommandOnBank.getCommand() == Command::PDNPX || lastCommandOnBank.getCommand() == Command::PDNAX)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), config.memSpec.tXP);
|
||||
}
|
||||
else if (lastCommandOnBank.getCommand() == Command::SREFX)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), config.memSpec.tXSR);
|
||||
}
|
||||
else
|
||||
reportFatal("Activate Checker", "Activate can not follow " + commandToString(lastCommandOnBank.getCommand()));
|
||||
config.memSpec.tRP);
|
||||
} else if (lastCommandOnBank.getCommand() == Command::ReadA) {
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(),
|
||||
config.memSpec.tRTP + config.memSpec.tRP);
|
||||
} else if (lastCommandOnBank.getCommand() == Command::WriteA) {
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(),
|
||||
config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR +
|
||||
config.memSpec.tRP);
|
||||
} else if (lastCommandOnBank.getCommand() == Command::AutoRefresh) {
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(),
|
||||
config.memSpec.tRFC);
|
||||
} else if (lastCommandOnBank.getCommand() == Command::PDNPX
|
||||
|| lastCommandOnBank.getCommand() == Command::PDNAX) {
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(),
|
||||
config.memSpec.tXP);
|
||||
} else if (lastCommandOnBank.getCommand() == Command::SREFX) {
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(),
|
||||
config.memSpec.tXSR);
|
||||
} else
|
||||
reportFatal("Activate Checker",
|
||||
"Activate can not follow " + commandToString(lastCommandOnBank.getCommand()));
|
||||
}
|
||||
|
||||
delay_to_satisfy_activateToActivate_sameBank(command);
|
||||
|
||||
while (!(state.bus.isFree(command.getStart()) && satsfies_activateToActivate_differentBank(command)
|
||||
&& satisfies_nActivateWindow(command)))
|
||||
{
|
||||
while (!(state.bus.isFree(command.getStart())
|
||||
&& satsfies_activateToActivate_differentBank(command)
|
||||
&& satisfies_nActivateWindow(command))) {
|
||||
command.delayStart(config.memSpec.clk);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ActivateChecker::delay_to_satisfy_activateToActivate_sameBank(ScheduledCommand& command) const
|
||||
void ActivateChecker::delay_to_satisfy_activateToActivate_sameBank(
|
||||
ScheduledCommand &command) const
|
||||
{
|
||||
ScheduledCommand lastActivateOnBank = state.getLastCommand(Command::Activate, command.getBank());
|
||||
if (lastActivateOnBank.isValidCommand())
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastActivateOnBank.getStart(), config.memSpec.tRC);
|
||||
ScheduledCommand lastActivateOnBank = state.getLastCommand(Command::Activate,
|
||||
command.getBank());
|
||||
if (lastActivateOnBank.isValidCommand()) {
|
||||
command.establishMinDistanceFromStart(lastActivateOnBank.getStart(),
|
||||
config.memSpec.tRC);
|
||||
}
|
||||
}
|
||||
|
||||
bool ActivateChecker::satsfies_activateToActivate_differentBank(ScheduledCommand& command) const
|
||||
bool ActivateChecker::satsfies_activateToActivate_differentBank(
|
||||
ScheduledCommand &command) const
|
||||
{
|
||||
for (auto act : state.lastActivates)
|
||||
{
|
||||
for (auto act : state.lastActivates) {
|
||||
sc_time time = act.first;
|
||||
sc_time tRRD = (command.getBankGroup() == act.second.getBankGroup()) ? config.memSpec.tRRD_L : config.memSpec.tRRD_S;
|
||||
sc_time tRRD = (command.getBankGroup() == act.second.getBankGroup()) ?
|
||||
config.memSpec.tRRD_L : config.memSpec.tRRD_S;
|
||||
|
||||
if ((time < command.getStart() && command.getStart() - time < tRRD)
|
||||
|| (command.getStart() <= time && time - command.getStart() < tRRD))
|
||||
@@ -114,23 +114,21 @@ bool ActivateChecker::satsfies_activateToActivate_differentBank(ScheduledCommand
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ActivateChecker::satisfies_nActivateWindow(ScheduledCommand& command) const
|
||||
bool ActivateChecker::satisfies_nActivateWindow(ScheduledCommand &command) const
|
||||
{
|
||||
/*
|
||||
* there may be activates scheduled in the future, so emplace
|
||||
* command in a copied set (not necessarily the last in time),
|
||||
* and check if the n-act constraint holds for the whole set.
|
||||
*/
|
||||
if (state.lastActivates.size() >= config.memSpec.nActivate)
|
||||
{
|
||||
if (state.lastActivates.size() >= config.memSpec.nActivate) {
|
||||
map<sc_time, ScheduledCommand> lastActivates = state.lastActivates;
|
||||
lastActivates.emplace(command.getStart(), command);
|
||||
auto upper = lastActivates.begin();
|
||||
advance(upper, config.memSpec.nActivate);
|
||||
auto lower = lastActivates.begin();
|
||||
|
||||
while (upper != lastActivates.end())
|
||||
{
|
||||
while (upper != lastActivates.end()) {
|
||||
if (upper->first - lower->first < config.memSpec.tNAW)
|
||||
return false;
|
||||
++upper;
|
||||
|
||||
@@ -45,17 +45,20 @@
|
||||
class ActivateChecker: public ICommandChecker
|
||||
{
|
||||
public:
|
||||
ActivateChecker(const Configuration& config, ControllerState& state) : config(config), state(state){}
|
||||
virtual ~ActivateChecker(){}
|
||||
ActivateChecker(const Configuration &config,
|
||||
ControllerState &state) : config(config), state(state) {}
|
||||
virtual ~ActivateChecker() {}
|
||||
|
||||
virtual void delayToSatisfyConstraints(ScheduledCommand& command) const override;
|
||||
virtual void delayToSatisfyConstraints(ScheduledCommand &command) const
|
||||
override;
|
||||
private:
|
||||
const Configuration& config;
|
||||
ControllerState& state;//TODO make const
|
||||
const Configuration &config;
|
||||
ControllerState &state;//TODO make const
|
||||
|
||||
void delay_to_satisfy_activateToActivate_sameBank(ScheduledCommand& command) const;
|
||||
bool satsfies_activateToActivate_differentBank(ScheduledCommand& command) const;
|
||||
bool satisfies_nActivateWindow(ScheduledCommand& command) const;
|
||||
void delay_to_satisfy_activateToActivate_sameBank(ScheduledCommand &command)
|
||||
const;
|
||||
bool satsfies_activateToActivate_differentBank(ScheduledCommand &command) const;
|
||||
bool satisfies_nActivateWindow(ScheduledCommand &command) const;
|
||||
};
|
||||
|
||||
#endif /* ACTIVATESCHEDULER_H_ */
|
||||
|
||||
@@ -44,8 +44,8 @@
|
||||
class ICommandChecker
|
||||
{
|
||||
public:
|
||||
virtual ~ICommandChecker() {}
|
||||
virtual void delayToSatisfyConstraints(ScheduledCommand& command) const = 0;
|
||||
virtual ~ICommandChecker() {}
|
||||
virtual void delayToSatisfyConstraints(ScheduledCommand &command) const = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -38,77 +38,86 @@
|
||||
#include "PowerDownChecker.h"
|
||||
#include "../../TimingCalculation.h"
|
||||
|
||||
sc_time PowerDownChecker::getTimeConstraintToEnterPowerDown(Command lastCmd, Command pdnCmd) const
|
||||
sc_time PowerDownChecker::getTimeConstraintToEnterPowerDown(Command lastCmd,
|
||||
Command pdnCmd) const
|
||||
{
|
||||
sc_assert(pdnCmd == Command::SREF || pdnCmd == Command::PDNA || pdnCmd == Command::PDNP);
|
||||
sc_assert(pdnCmd == Command::SREF || pdnCmd == Command::PDNA
|
||||
|| pdnCmd == Command::PDNP);
|
||||
|
||||
sc_time constraint;
|
||||
sc_time constraint;
|
||||
|
||||
if (lastCmd == Command::Read || lastCmd == Command::ReadA) {
|
||||
constraint = config.memSpec.tRL + getReadAccessTime() + config.memSpec.clk;
|
||||
} else if (lastCmd == Command::Write) {
|
||||
constraint = config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR;
|
||||
} else if (lastCmd == Command::WriteA) {
|
||||
constraint = config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR + config.memSpec.clk;
|
||||
} else if (lastCmd == Command::AutoRefresh) {
|
||||
constraint = config.memSpec.tRFC;
|
||||
} else if (lastCmd == Command::PDNPX || lastCmd == Command::PDNAX) {
|
||||
constraint = config.memSpec.tXP;
|
||||
} else if (lastCmd == Command::SREFX) {
|
||||
constraint = config.memSpec.tXSR;
|
||||
} else if(lastCmd == Command::Precharge || lastCmd == Command::PrechargeAll) {
|
||||
constraint = config.memSpec.tRP;
|
||||
} else {
|
||||
reportFatal("Powerdown checker", commandToString(pdnCmd) + " can not follow " + commandToString(lastCmd));
|
||||
}
|
||||
if (lastCmd == Command::Read || lastCmd == Command::ReadA) {
|
||||
constraint = config.memSpec.tRL + getReadAccessTime() + config.memSpec.clk;
|
||||
} else if (lastCmd == Command::Write) {
|
||||
constraint = config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR;
|
||||
} else if (lastCmd == Command::WriteA) {
|
||||
constraint = config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR +
|
||||
config.memSpec.clk;
|
||||
} else if (lastCmd == Command::AutoRefresh) {
|
||||
constraint = config.memSpec.tRFC;
|
||||
} else if (lastCmd == Command::PDNPX || lastCmd == Command::PDNAX) {
|
||||
constraint = config.memSpec.tXP;
|
||||
} else if (lastCmd == Command::SREFX) {
|
||||
constraint = config.memSpec.tXSR;
|
||||
} else if (lastCmd == Command::Precharge || lastCmd == Command::PrechargeAll) {
|
||||
constraint = config.memSpec.tRP;
|
||||
} else {
|
||||
reportFatal("Powerdown checker",
|
||||
commandToString(pdnCmd) + " can not follow " + commandToString(lastCmd));
|
||||
}
|
||||
|
||||
return constraint;
|
||||
return constraint;
|
||||
}
|
||||
|
||||
void PowerDownChecker::delayToSatisfyConstraints(ScheduledCommand &command) const
|
||||
void PowerDownChecker::delayToSatisfyConstraints(ScheduledCommand &command)
|
||||
const
|
||||
{
|
||||
sc_assert(command.commandIsIn({Command::PDNA, Command::PDNP, Command::SREF, Command::PDNAX, Command::PDNPX, Command::SREFX}));
|
||||
sc_assert(command.commandIsIn({Command::PDNA, Command::PDNP, Command::SREF, Command::PDNAX, Command::PDNPX, Command::SREFX}));
|
||||
|
||||
// Power Down commmand (one of the listed above)
|
||||
Command pdnCmd = command.getCommand();
|
||||
Bank bank = command.getBank();
|
||||
// Power Down commmand (one of the listed above)
|
||||
Command pdnCmd = command.getCommand();
|
||||
Bank bank = command.getBank();
|
||||
|
||||
sc_time timeConstraint;
|
||||
sc_time timeConstraint;
|
||||
|
||||
if (pdnCmd == Command::PDNA || pdnCmd == Command::PDNP || pdnCmd == Command::SREF) {
|
||||
// Entering in one of the Power Down modes:
|
||||
// PDNA - Active Power Down
|
||||
// PDNP - Precharge Power Down
|
||||
// SREF - Self Refresh
|
||||
if (pdnCmd == Command::PDNA || pdnCmd == Command::PDNP
|
||||
|| pdnCmd == Command::SREF) {
|
||||
// Entering in one of the Power Down modes:
|
||||
// PDNA - Active Power Down
|
||||
// PDNP - Precharge Power Down
|
||||
// SREF - Self Refresh
|
||||
|
||||
// Get the last scheduled command on this bank
|
||||
ScheduledCommand lastSchedCmdOnBank = state.getLastScheduledCommand(bank);
|
||||
// Get the last scheduled command on this bank
|
||||
ScheduledCommand lastSchedCmdOnBank = state.getLastScheduledCommand(bank);
|
||||
|
||||
if (lastSchedCmdOnBank.isValidCommand()) {
|
||||
// Get the start time for the last scheduled command on this bank
|
||||
sc_time lastSchedCmdOnBankStart = lastSchedCmdOnBank.getStart();
|
||||
// Get the last command on this bank itself
|
||||
Command lastCmdBank = lastSchedCmdOnBank.getCommand();
|
||||
// Get the start time for the last scheduled command on this bank
|
||||
sc_time lastSchedCmdOnBankStart = lastSchedCmdOnBank.getStart();
|
||||
// Get the last command on this bank itself
|
||||
Command lastCmdBank = lastSchedCmdOnBank.getCommand();
|
||||
|
||||
timeConstraint = getTimeConstraintToEnterPowerDown(lastCmdBank, pdnCmd);
|
||||
timeConstraint = getTimeConstraintToEnterPowerDown(lastCmdBank, pdnCmd);
|
||||
|
||||
command.establishMinDistanceFromStart(lastSchedCmdOnBankStart, timeConstraint);
|
||||
command.establishMinDistanceFromStart(lastSchedCmdOnBankStart, timeConstraint);
|
||||
}
|
||||
|
||||
} else if (pdnCmd == Command::PDNAX) {
|
||||
// Leaving Active Power Down
|
||||
timeConstraint = config.memSpec.tCKE;
|
||||
command.establishMinDistanceFromStart(state.getLastCommand(Command::PDNA, bank).getStart(), timeConstraint);
|
||||
command.establishMinDistanceFromStart(state.getLastCommand(Command::PDNA,
|
||||
bank).getStart(), timeConstraint);
|
||||
} else if (pdnCmd == Command::PDNPX) {
|
||||
// Leaving Precharge Power Down
|
||||
timeConstraint = config.memSpec.tCKE;
|
||||
command.establishMinDistanceFromStart(state.getLastCommand(Command::PDNP, bank).getStart(), timeConstraint);
|
||||
command.establishMinDistanceFromStart(state.getLastCommand(Command::PDNP,
|
||||
bank).getStart(), timeConstraint);
|
||||
} else if (pdnCmd == Command::SREFX) {
|
||||
// Leaving Self Refresh
|
||||
timeConstraint = config.memSpec.tCKESR;
|
||||
command.establishMinDistanceFromStart(state.getLastCommand(Command::SREF, bank).getStart(), timeConstraint);
|
||||
command.establishMinDistanceFromStart(state.getLastCommand(Command::SREF,
|
||||
bank).getStart(), timeConstraint);
|
||||
}
|
||||
|
||||
state.bus.moveCommandToNextFreeSlot(command);
|
||||
state.bus.moveCommandToNextFreeSlot(command);
|
||||
}
|
||||
|
||||
|
||||
@@ -46,15 +46,18 @@
|
||||
class PowerDownChecker : public ICommandChecker
|
||||
{
|
||||
public:
|
||||
PowerDownChecker(const Configuration &config, ControllerState &state) : config(config), state(state) {}
|
||||
virtual ~PowerDownChecker() {}
|
||||
PowerDownChecker(const Configuration &config,
|
||||
ControllerState &state) : config(config), state(state) {}
|
||||
virtual ~PowerDownChecker() {}
|
||||
|
||||
virtual void delayToSatisfyConstraints(ScheduledCommand& command) const override;
|
||||
virtual void delayToSatisfyConstraints(ScheduledCommand &command) const
|
||||
override;
|
||||
|
||||
private:
|
||||
const Configuration &config;
|
||||
ControllerState &state;
|
||||
sc_time getTimeConstraintToEnterPowerDown(Command lastCmd, Command pdnCmd) const;
|
||||
const Configuration &config;
|
||||
ControllerState &state;
|
||||
sc_time getTimeConstraintToEnterPowerDown(Command lastCmd,
|
||||
Command pdnCmd) const;
|
||||
};
|
||||
|
||||
#endif /* POWERDOWNCHECKER_H_ */
|
||||
|
||||
@@ -39,62 +39,55 @@
|
||||
#include "../../TimingCalculation.h"
|
||||
|
||||
|
||||
void PrechargeAllChecker::delayToSatisfyConstraints(ScheduledCommand& command) const
|
||||
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)
|
||||
{
|
||||
for (unsigned int bank = 0; bank < config.memSpec.NumberOfBanks; ++bank) {
|
||||
ScheduledCommand lastCommand = state.getLastScheduledCommand(Bank(bank));
|
||||
if (lastCommand.isValidCommand())
|
||||
{
|
||||
if(lastCommand.getCommand() == Command::Precharge)
|
||||
{
|
||||
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.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tRTP + config.memSpec.tRP);
|
||||
}
|
||||
else if (lastCommand.getCommand() == Command::Write)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR);
|
||||
}
|
||||
else if(lastCommand.getCommand() == Command::WriteA)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR + config.memSpec.tRP);
|
||||
}
|
||||
else if (lastCommand.getCommand() == Command::AutoRefresh)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tRFC);
|
||||
}
|
||||
else if (lastCommand.getCommand() == Command::PDNAX || lastCommand.getCommand() == Command::PDNPX)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tXP);
|
||||
}
|
||||
else if (lastCommand.getCommand() == Command::SREFX)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tXSR);
|
||||
}
|
||||
else
|
||||
if (lastCommand.isValidCommand()) {
|
||||
if (lastCommand.getCommand() == Command::Precharge) {
|
||||
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.establishMinDistanceFromStart(lastCommand.getStart(),
|
||||
config.memSpec.tRTP + config.memSpec.tRP);
|
||||
} else if (lastCommand.getCommand() == Command::Write) {
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(),
|
||||
config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR);
|
||||
} else if (lastCommand.getCommand() == Command::WriteA) {
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(),
|
||||
config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR +
|
||||
config.memSpec.tRP);
|
||||
} else if (lastCommand.getCommand() == Command::AutoRefresh) {
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(),
|
||||
config.memSpec.tRFC);
|
||||
} else if (lastCommand.getCommand() == Command::PDNAX
|
||||
|| lastCommand.getCommand() == Command::PDNPX) {
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(),
|
||||
config.memSpec.tXP);
|
||||
} else if (lastCommand.getCommand() == Command::SREFX) {
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(),
|
||||
config.memSpec.tXSR);
|
||||
} else
|
||||
reportFatal("Precharge All Checker",
|
||||
"Precharge All can not follow " + commandToString(lastCommand.getCommand()));
|
||||
"Precharge All can not follow " + commandToString(lastCommand.getCommand()));
|
||||
}
|
||||
}
|
||||
|
||||
ScheduledCommand lastActivate = state.getLastCommand(Command::Activate, command.getBank());
|
||||
if (lastActivate.isValidCommand())
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastActivate.getStart(), config.memSpec.tRAS);
|
||||
ScheduledCommand lastActivate = state.getLastCommand(Command::Activate,
|
||||
command.getBank());
|
||||
if (lastActivate.isValidCommand()) {
|
||||
command.establishMinDistanceFromStart(lastActivate.getStart(),
|
||||
config.memSpec.tRAS);
|
||||
}
|
||||
|
||||
state.bus.moveCommandToNextFreeSlot(command);
|
||||
|
||||
@@ -45,19 +45,20 @@
|
||||
class PrechargeAllChecker: public ICommandChecker
|
||||
{
|
||||
public:
|
||||
PrechargeAllChecker(const Configuration& config, ControllerState& state) :
|
||||
config(config), state(state)
|
||||
{
|
||||
}
|
||||
virtual ~PrechargeAllChecker()
|
||||
{
|
||||
}
|
||||
PrechargeAllChecker(const Configuration &config, ControllerState &state) :
|
||||
config(config), state(state)
|
||||
{
|
||||
}
|
||||
virtual ~PrechargeAllChecker()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void delayToSatisfyConstraints(ScheduledCommand& command) const override;
|
||||
virtual void delayToSatisfyConstraints(ScheduledCommand &command) const
|
||||
override;
|
||||
|
||||
private:
|
||||
const Configuration& config;
|
||||
ControllerState& state;
|
||||
const Configuration &config;
|
||||
ControllerState &state;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -38,47 +38,45 @@
|
||||
#include "../../TimingCalculation.h"
|
||||
|
||||
|
||||
void PrechargeChecker::delayToSatisfyConstraints(ScheduledCommand& command) const
|
||||
void PrechargeChecker::delayToSatisfyConstraints(ScheduledCommand &command)
|
||||
const
|
||||
{
|
||||
//return;
|
||||
sc_assert(command.getCommand() == Command::Precharge);
|
||||
|
||||
ScheduledCommand lastCommand = state.getLastScheduledCommand(command.getBank());
|
||||
|
||||
if (lastCommand.isValidCommand())
|
||||
{
|
||||
if (lastCommand.isValidCommand()) {
|
||||
// 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.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tRP);
|
||||
}
|
||||
else if(lastCommand.getCommand() == Command::Activate)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tRCD);
|
||||
if (lastCommand.getCommand() == Command::Precharge) {
|
||||
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.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR);
|
||||
else if (lastCommand.getCommand() == Command::Read) {
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(),
|
||||
config.memSpec.tRTP);
|
||||
} else if (lastCommand.getCommand() == Command::Write) {
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(),
|
||||
config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR);
|
||||
|
||||
}
|
||||
else if (lastCommand.getCommand() == Command::PDNAX)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tXP);
|
||||
}
|
||||
else
|
||||
reportFatal("Precharge Checker", "Precharge can not follow " + commandToString(lastCommand.getCommand()));
|
||||
} else if (lastCommand.getCommand() == Command::PDNAX) {
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(),
|
||||
config.memSpec.tXP);
|
||||
} else
|
||||
reportFatal("Precharge Checker",
|
||||
"Precharge can not follow " + commandToString(lastCommand.getCommand()));
|
||||
}
|
||||
|
||||
ScheduledCommand lastActivate = state.getLastCommand(Command::Activate, command.getBank());
|
||||
if (lastActivate.isValidCommand())
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastActivate.getStart(), config.memSpec.tRAS);
|
||||
ScheduledCommand lastActivate = state.getLastCommand(Command::Activate,
|
||||
command.getBank());
|
||||
if (lastActivate.isValidCommand()) {
|
||||
command.establishMinDistanceFromStart(lastActivate.getStart(),
|
||||
config.memSpec.tRAS);
|
||||
}
|
||||
|
||||
state.bus.moveCommandToNextFreeSlot(command);
|
||||
|
||||
@@ -45,13 +45,15 @@
|
||||
class PrechargeChecker: public ICommandChecker
|
||||
{
|
||||
public:
|
||||
PrechargeChecker(const Configuration& config, ControllerState& state) : config(config), state(state) {}
|
||||
virtual ~PrechargeChecker() {}
|
||||
virtual void delayToSatisfyConstraints(ScheduledCommand& command) const override;
|
||||
PrechargeChecker(const Configuration &config,
|
||||
ControllerState &state) : config(config), state(state) {}
|
||||
virtual ~PrechargeChecker() {}
|
||||
virtual void delayToSatisfyConstraints(ScheduledCommand &command) const
|
||||
override;
|
||||
|
||||
private:
|
||||
const Configuration& config;
|
||||
ControllerState& state;
|
||||
const Configuration &config;
|
||||
ControllerState &state;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -41,44 +41,40 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
void ReadChecker::delayToSatisfyConstraints(ScheduledCommand& command) const
|
||||
void ReadChecker::delayToSatisfyConstraints(ScheduledCommand &command) const
|
||||
{
|
||||
sc_assert(command.getCommand() == Command::Read || command.getCommand() == Command::ReadA);
|
||||
sc_assert(command.getCommand() == Command::Read
|
||||
|| command.getCommand() == Command::ReadA);
|
||||
delayToSatisfyDLL(command);
|
||||
ScheduledCommand lastCommand = state.getLastScheduledCommand(command.getBank());
|
||||
|
||||
if (lastCommand.isValidCommand())
|
||||
{
|
||||
if (lastCommand.getCommand() == Command::Activate)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tRCD);
|
||||
}
|
||||
else if (lastCommand.getCommand() == Command::Read)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), ReadChecker::readToRead(lastCommand,command));
|
||||
}
|
||||
else if (lastCommand.getCommand() == Command::Write)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), ReadChecker::writeToRead(lastCommand, command));
|
||||
}
|
||||
else if (lastCommand.getCommand() == Command::PDNPX || lastCommand.getCommand() == Command::PDNAX)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tXP);
|
||||
}
|
||||
else
|
||||
reportFatal("Read Checker", "Read can not follow " + commandToString(lastCommand.getCommand()));
|
||||
if (lastCommand.isValidCommand()) {
|
||||
if (lastCommand.getCommand() == Command::Activate) {
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(),
|
||||
config.memSpec.tRCD);
|
||||
} else if (lastCommand.getCommand() == Command::Read) {
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(),
|
||||
ReadChecker::readToRead(lastCommand, command));
|
||||
} else if (lastCommand.getCommand() == Command::Write) {
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(),
|
||||
ReadChecker::writeToRead(lastCommand, command));
|
||||
} else if (lastCommand.getCommand() == Command::PDNPX
|
||||
|| lastCommand.getCommand() == Command::PDNAX) {
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(),
|
||||
config.memSpec.tXP);
|
||||
} else
|
||||
reportFatal("Read Checker",
|
||||
"Read can not follow " + commandToString(lastCommand.getCommand()));
|
||||
}
|
||||
|
||||
while (!state.bus.isFree(command.getStart()) || collidesOnDataStrobe(command))
|
||||
{
|
||||
while (!state.bus.isFree(command.getStart()) || collidesOnDataStrobe(command)) {
|
||||
command.delayStart(config.memSpec.clk);
|
||||
}
|
||||
}
|
||||
|
||||
bool ReadChecker::collidesOnDataStrobe(ScheduledCommand& read) const
|
||||
bool ReadChecker::collidesOnDataStrobe(ScheduledCommand &read) const
|
||||
{
|
||||
for (ScheduledCommand& strobeCommand : state.lastDataStrobeCommands)
|
||||
{
|
||||
for (ScheduledCommand &strobeCommand : state.lastDataStrobeCommands) {
|
||||
if (collidesWithStrobeCommand(read, strobeCommand))
|
||||
return true;
|
||||
}
|
||||
@@ -86,51 +82,63 @@ bool ReadChecker::collidesOnDataStrobe(ScheduledCommand& read) const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ReadChecker::collidesWithStrobeCommand(ScheduledCommand& read, ScheduledCommand& strobeCommand) const
|
||||
bool ReadChecker::collidesWithStrobeCommand(ScheduledCommand &read,
|
||||
ScheduledCommand &strobeCommand) const
|
||||
{
|
||||
if (strobeCommand.getCommand() == Command::Read || strobeCommand.getCommand() == Command::ReadA)
|
||||
{
|
||||
return getDistance(read.getStart(),strobeCommand.getStart()) < ReadChecker::readToRead(strobeCommand,read);
|
||||
}
|
||||
else if (strobeCommand.getCommand() == Command::Write || strobeCommand.getCommand() == Command::WriteA)
|
||||
{
|
||||
if (strobeCommand.getCommand() == Command::Read
|
||||
|| strobeCommand.getCommand() == Command::ReadA) {
|
||||
return getDistance(read.getStart(),
|
||||
strobeCommand.getStart()) < ReadChecker::readToRead(strobeCommand, read);
|
||||
} else if (strobeCommand.getCommand() == Command::Write
|
||||
|| strobeCommand.getCommand() == Command::WriteA) {
|
||||
if (strobeCommand.getStart() >= read.getStart())
|
||||
return getDistance(read.getStart(), strobeCommand.getStart()) < WriteChecker::readToWrite(read,strobeCommand);
|
||||
return getDistance(read.getStart(),
|
||||
strobeCommand.getStart()) < WriteChecker::readToWrite(read, strobeCommand);
|
||||
else
|
||||
return getDistance(strobeCommand.getStart(), read.getStart()) < ReadChecker::writeToRead(strobeCommand, read);
|
||||
}
|
||||
else
|
||||
{
|
||||
return getDistance(strobeCommand.getStart(),
|
||||
read.getStart()) < ReadChecker::writeToRead(strobeCommand, read);
|
||||
} else {
|
||||
reportFatal("Read Checker",
|
||||
"Invalid strobeCommand in data strobe commands " + commandToString(strobeCommand.getCommand()));
|
||||
"Invalid strobeCommand in data strobe commands " + commandToString(
|
||||
strobeCommand.getCommand()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void ReadChecker::delayToSatisfyDLL(ScheduledCommand& read) const
|
||||
void ReadChecker::delayToSatisfyDLL(ScheduledCommand &read) const
|
||||
{
|
||||
ScheduledCommand lastSREFX = state.getLastCommand(Command::SREFX, read.getBank());
|
||||
ScheduledCommand lastSREFX = state.getLastCommand(Command::SREFX,
|
||||
read.getBank());
|
||||
if (lastSREFX.isValidCommand())
|
||||
read.establishMinDistanceFromStart(lastSREFX.getStart(), config.memSpec.tXSRDLL);
|
||||
read.establishMinDistanceFromStart(lastSREFX.getStart(),
|
||||
config.memSpec.tXSRDLL);
|
||||
}
|
||||
|
||||
sc_time ReadChecker::readToRead(ScheduledCommand& firstRead, ScheduledCommand& secondRead)
|
||||
sc_time ReadChecker::readToRead(ScheduledCommand &firstRead,
|
||||
ScheduledCommand &secondRead)
|
||||
{
|
||||
sc_assert(firstRead.getCommand() == Command::Read || firstRead.getCommand() == Command::ReadA);
|
||||
sc_assert(secondRead.getCommand() == Command::Read || secondRead.getCommand() == Command::ReadA);
|
||||
sc_assert(firstRead.getCommand() == Command::Read
|
||||
|| firstRead.getCommand() == Command::ReadA);
|
||||
sc_assert(secondRead.getCommand() == Command::Read
|
||||
|| secondRead.getCommand() == Command::ReadA);
|
||||
|
||||
MemSpec& config = Configuration::getInstance().memSpec;
|
||||
sc_time tCCD = (firstRead.getBankGroup() == secondRead.getBankGroup()) ? config.tCCD_L : config.tCCD_S;
|
||||
MemSpec &config = Configuration::getInstance().memSpec;
|
||||
sc_time tCCD = (firstRead.getBankGroup() == secondRead.getBankGroup()) ?
|
||||
config.tCCD_L : config.tCCD_S;
|
||||
return max(tCCD, getReadAccessTime());
|
||||
}
|
||||
|
||||
sc_time ReadChecker::writeToRead(ScheduledCommand& write, ScheduledCommand& read)
|
||||
sc_time ReadChecker::writeToRead(ScheduledCommand &write,
|
||||
ScheduledCommand &read)
|
||||
{
|
||||
sc_assert(read.getCommand() == Command::Read || read.getCommand() == Command::ReadA);
|
||||
sc_assert(write.getCommand() == Command::Write || write.getCommand() == Command::WriteA);
|
||||
sc_assert(read.getCommand() == Command::Read
|
||||
|| read.getCommand() == Command::ReadA);
|
||||
sc_assert(write.getCommand() == Command::Write
|
||||
|| write.getCommand() == Command::WriteA);
|
||||
|
||||
MemSpec& config = Configuration::getInstance().memSpec;
|
||||
sc_time tWTR = (write.getBankGroup() == read.getBankGroup()) ? config.tWTR_L : config.tWTR_S;
|
||||
MemSpec &config = Configuration::getInstance().memSpec;
|
||||
sc_time tWTR = (write.getBankGroup() == read.getBankGroup()) ? config.tWTR_L :
|
||||
config.tWTR_S;
|
||||
return config.tWL + getWriteAccessTime() + tWTR;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,21 +44,25 @@
|
||||
class ReadChecker: public ICommandChecker
|
||||
{
|
||||
public:
|
||||
ReadChecker(Configuration& config, ControllerState& state) : config(config), state(state) {}
|
||||
virtual ~ReadChecker() {}
|
||||
ReadChecker(Configuration &config, ControllerState &state) : config(config),
|
||||
state(state) {}
|
||||
virtual ~ReadChecker() {}
|
||||
|
||||
virtual void delayToSatisfyConstraints(ScheduledCommand& command) const override;
|
||||
virtual void delayToSatisfyConstraints(ScheduledCommand &command) const
|
||||
override;
|
||||
|
||||
static sc_time readToRead(ScheduledCommand& firstRead, ScheduledCommand& secondRead);
|
||||
static sc_time writeToRead(ScheduledCommand& write, ScheduledCommand& read);
|
||||
static sc_time readToRead(ScheduledCommand &firstRead,
|
||||
ScheduledCommand &secondRead);
|
||||
static sc_time writeToRead(ScheduledCommand &write, ScheduledCommand &read);
|
||||
|
||||
private:
|
||||
const Configuration& config;
|
||||
ControllerState& state;
|
||||
const Configuration &config;
|
||||
ControllerState &state;
|
||||
|
||||
void delayToSatisfyDLL(ScheduledCommand& read) const;
|
||||
bool collidesOnDataStrobe(ScheduledCommand& read) const;
|
||||
bool collidesWithStrobeCommand(ScheduledCommand& read, ScheduledCommand& strobeCommand) const;
|
||||
void delayToSatisfyDLL(ScheduledCommand &read) const;
|
||||
bool collidesOnDataStrobe(ScheduledCommand &read) const;
|
||||
bool collidesWithStrobeCommand(ScheduledCommand &read,
|
||||
ScheduledCommand &strobeCommand) const;
|
||||
};
|
||||
|
||||
#endif /* READCHECKER_H_ */
|
||||
|
||||
@@ -38,81 +38,71 @@
|
||||
#include "RefreshChecker.h"
|
||||
#include "../../TimingCalculation.h"
|
||||
|
||||
void RefreshChecker::delayToSatisfyConstraints(ScheduledCommand& command) const
|
||||
void RefreshChecker::delayToSatisfyConstraints(ScheduledCommand &command) const
|
||||
{
|
||||
sc_assert(command.getCommand() == Command::AutoRefresh);
|
||||
|
||||
if(config.BankwiseLogic)
|
||||
{
|
||||
ScheduledCommand lastCommandOnBank = state.getLastScheduledCommand(command.getBank());
|
||||
if (config.BankwiseLogic) {
|
||||
ScheduledCommand lastCommandOnBank = state.getLastScheduledCommand(
|
||||
command.getBank());
|
||||
|
||||
if (lastCommandOnBank.isValidCommand())
|
||||
{
|
||||
if (lastCommandOnBank.getCommand() == Command::Precharge || lastCommandOnBank.getCommand() == Command::PrechargeAll)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), config.memSpec.tRP);
|
||||
}
|
||||
else if (lastCommandOnBank.getCommand() == Command::ReadA)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), config.memSpec.tRTP + config.memSpec.tRP);
|
||||
}
|
||||
else if (lastCommandOnBank.getCommand() == Command::WriteA)
|
||||
{
|
||||
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.establishMinDistanceFromStart(lastCommandOnBank.getStart(), config.memSpec.tXP);
|
||||
}
|
||||
else if (lastCommandOnBank.getCommand() == Command::SREFX)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), config.memSpec.tXSR);
|
||||
}
|
||||
else if (lastCommandOnBank.getCommand() == Command::AutoRefresh)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(), config.memSpec.tRFC);
|
||||
}
|
||||
else
|
||||
reportFatal("Refresh Checker", "Refresh can not follow " + commandToString(lastCommandOnBank.getCommand()));
|
||||
if (lastCommandOnBank.isValidCommand()) {
|
||||
if (lastCommandOnBank.getCommand() == Command::Precharge
|
||||
|| lastCommandOnBank.getCommand() == Command::PrechargeAll) {
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(),
|
||||
config.memSpec.tRP);
|
||||
} else if (lastCommandOnBank.getCommand() == Command::ReadA) {
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(),
|
||||
config.memSpec.tRTP + config.memSpec.tRP);
|
||||
} else if (lastCommandOnBank.getCommand() == Command::WriteA) {
|
||||
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.establishMinDistanceFromStart(lastCommandOnBank.getStart(),
|
||||
config.memSpec.tXP);
|
||||
} else if (lastCommandOnBank.getCommand() == Command::SREFX) {
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(),
|
||||
config.memSpec.tXSR);
|
||||
} else if (lastCommandOnBank.getCommand() == Command::AutoRefresh) {
|
||||
command.establishMinDistanceFromStart(lastCommandOnBank.getStart(),
|
||||
config.memSpec.tRFC);
|
||||
} else
|
||||
reportFatal("Refresh Checker",
|
||||
"Refresh can not follow " + commandToString(lastCommandOnBank.getCommand()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned int bank = 0; bank < config.memSpec.NumberOfBanks; ++bank)
|
||||
{
|
||||
} else {
|
||||
for (unsigned int bank = 0; bank < config.memSpec.NumberOfBanks; ++bank) {
|
||||
ScheduledCommand lastCommand = state.getLastScheduledCommand(Bank(bank));
|
||||
if (lastCommand.isValidCommand())
|
||||
{
|
||||
if(lastCommand.getCommand() == Command::Precharge || lastCommand.getCommand() == Command::PrechargeAll)
|
||||
{
|
||||
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::ReadA)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tRTP + config.memSpec.tRP);
|
||||
}
|
||||
else if(lastCommand.getCommand() == Command::WriteA)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR + config.memSpec.tRP);
|
||||
}
|
||||
else if (lastCommand.getCommand() == Command::PDNAX || lastCommand.getCommand() == Command::PDNPX)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tXP);
|
||||
}
|
||||
else if (lastCommand.getCommand() == Command::SREFX)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tXSR);
|
||||
}
|
||||
else if (lastCommand.getCommand() == Command::AutoRefresh)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tRFC);
|
||||
}
|
||||
else
|
||||
reportFatal("Refresh Checker", "Refresh can not follow " + commandToString(lastCommand.getCommand()));
|
||||
if (lastCommand.isValidCommand()) {
|
||||
if (lastCommand.getCommand() == Command::Precharge
|
||||
|| lastCommand.getCommand() == Command::PrechargeAll) {
|
||||
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::ReadA) {
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(),
|
||||
config.memSpec.tRTP + config.memSpec.tRP);
|
||||
} else if (lastCommand.getCommand() == Command::WriteA) {
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(),
|
||||
config.memSpec.tWL + getWriteAccessTime() + config.memSpec.tWR +
|
||||
config.memSpec.tRP);
|
||||
} else if (lastCommand.getCommand() == Command::PDNAX
|
||||
|| lastCommand.getCommand() == Command::PDNPX) {
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(),
|
||||
config.memSpec.tXP);
|
||||
} else if (lastCommand.getCommand() == Command::SREFX) {
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(),
|
||||
config.memSpec.tXSR);
|
||||
} else if (lastCommand.getCommand() == Command::AutoRefresh) {
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(),
|
||||
config.memSpec.tRFC);
|
||||
} else
|
||||
reportFatal("Refresh Checker",
|
||||
"Refresh can not follow " + commandToString(lastCommand.getCommand()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,19 +46,20 @@
|
||||
class RefreshChecker: public ICommandChecker
|
||||
{
|
||||
public:
|
||||
RefreshChecker(const Configuration& config, ControllerState& state) :
|
||||
config(config), state(state)
|
||||
{
|
||||
}
|
||||
virtual ~RefreshChecker()
|
||||
{
|
||||
}
|
||||
RefreshChecker(const Configuration &config, ControllerState &state) :
|
||||
config(config), state(state)
|
||||
{
|
||||
}
|
||||
virtual ~RefreshChecker()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void delayToSatisfyConstraints(ScheduledCommand& command) const override;
|
||||
virtual void delayToSatisfyConstraints(ScheduledCommand &command) const
|
||||
override;
|
||||
|
||||
private:
|
||||
const Configuration& config;
|
||||
ControllerState& state;
|
||||
const Configuration &config;
|
||||
ControllerState &state;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -41,88 +41,93 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
void WriteChecker::delayToSatisfyConstraints(ScheduledCommand& command) const
|
||||
void WriteChecker::delayToSatisfyConstraints(ScheduledCommand &command) const
|
||||
{
|
||||
sc_assert(command.getCommand() == Command::Write || command.getCommand() == Command::WriteA);
|
||||
sc_assert(command.getCommand() == Command::Write
|
||||
|| command.getCommand() == Command::WriteA);
|
||||
|
||||
ScheduledCommand lastCommand = state.getLastScheduledCommand(command.getBank());
|
||||
ScheduledCommand lastCommand = state.getLastScheduledCommand(command.getBank());
|
||||
|
||||
if (lastCommand.isValidCommand())
|
||||
{
|
||||
if (lastCommand.getCommand() == Command::Activate)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tRCD);
|
||||
}
|
||||
else if (lastCommand.getCommand() == Command::Read)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), WriteChecker::readToWrite(lastCommand, command));
|
||||
}
|
||||
else if (lastCommand.getCommand() == Command::Write)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), WriteChecker::writeToWrite(lastCommand, command));
|
||||
}
|
||||
else if (lastCommand.getCommand() == Command::PDNPX || lastCommand.getCommand() == Command::PDNAX)
|
||||
{
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(), config.memSpec.tXP);
|
||||
}
|
||||
else
|
||||
reportFatal("Write Checker", "Write can not follow " + commandToString(lastCommand.getCommand()));
|
||||
}
|
||||
if (lastCommand.isValidCommand()) {
|
||||
if (lastCommand.getCommand() == Command::Activate) {
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(),
|
||||
config.memSpec.tRCD);
|
||||
} else if (lastCommand.getCommand() == Command::Read) {
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(),
|
||||
WriteChecker::readToWrite(lastCommand, command));
|
||||
} else if (lastCommand.getCommand() == Command::Write) {
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(),
|
||||
WriteChecker::writeToWrite(lastCommand, command));
|
||||
} else if (lastCommand.getCommand() == Command::PDNPX
|
||||
|| lastCommand.getCommand() == Command::PDNAX) {
|
||||
command.establishMinDistanceFromStart(lastCommand.getStart(),
|
||||
config.memSpec.tXP);
|
||||
} else
|
||||
reportFatal("Write Checker",
|
||||
"Write can not follow " + commandToString(lastCommand.getCommand()));
|
||||
}
|
||||
|
||||
while (!state.bus.isFree(command.getStart()) || collidesOnDataStrobe(command))
|
||||
{
|
||||
command.delayStart(config.memSpec.clk);
|
||||
}
|
||||
while (!state.bus.isFree(command.getStart()) || collidesOnDataStrobe(command)) {
|
||||
command.delayStart(config.memSpec.clk);
|
||||
}
|
||||
}
|
||||
|
||||
bool WriteChecker::collidesOnDataStrobe(ScheduledCommand& write) const
|
||||
bool WriteChecker::collidesOnDataStrobe(ScheduledCommand &write) const
|
||||
{
|
||||
for (ScheduledCommand& strobeCommand : state.lastDataStrobeCommands)
|
||||
{
|
||||
if (collidesWithStrobeCommand(write, strobeCommand))
|
||||
return true;
|
||||
}
|
||||
for (ScheduledCommand &strobeCommand : state.lastDataStrobeCommands) {
|
||||
if (collidesWithStrobeCommand(write, strobeCommand))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WriteChecker::collidesWithStrobeCommand(ScheduledCommand& write, ScheduledCommand& strobeCommand) const
|
||||
bool WriteChecker::collidesWithStrobeCommand(ScheduledCommand &write,
|
||||
ScheduledCommand &strobeCommand) const
|
||||
{
|
||||
if (strobeCommand.getCommand() == Command::Write || strobeCommand.getCommand() == Command::WriteA)
|
||||
{
|
||||
return getDistance(write.getStart(),strobeCommand.getStart()) < WriteChecker::writeToWrite(strobeCommand,write);
|
||||
}
|
||||
else if (strobeCommand.getCommand() == Command::Read || strobeCommand.getCommand() == Command::ReadA)
|
||||
{
|
||||
if (strobeCommand.getStart() >= write.getStart())
|
||||
return getDistance(write.getStart(),strobeCommand.getStart()) < ReadChecker::writeToRead(write, strobeCommand);
|
||||
else
|
||||
return getDistance(strobeCommand.getStart(), write.getStart()) < WriteChecker::readToWrite(strobeCommand, write);
|
||||
}
|
||||
else
|
||||
{
|
||||
reportFatal("Write Checker",
|
||||
"Invalid strobeCommand in data strobe commands " + commandToString(strobeCommand.getCommand()));
|
||||
return true;
|
||||
}
|
||||
if (strobeCommand.getCommand() == Command::Write
|
||||
|| strobeCommand.getCommand() == Command::WriteA) {
|
||||
return getDistance(write.getStart(),
|
||||
strobeCommand.getStart()) < WriteChecker::writeToWrite(strobeCommand, write);
|
||||
} else if (strobeCommand.getCommand() == Command::Read
|
||||
|| strobeCommand.getCommand() == Command::ReadA) {
|
||||
if (strobeCommand.getStart() >= write.getStart())
|
||||
return getDistance(write.getStart(),
|
||||
strobeCommand.getStart()) < ReadChecker::writeToRead(write, strobeCommand);
|
||||
else
|
||||
return getDistance(strobeCommand.getStart(),
|
||||
write.getStart()) < WriteChecker::readToWrite(strobeCommand, write);
|
||||
} else {
|
||||
reportFatal("Write Checker",
|
||||
"Invalid strobeCommand in data strobe commands " + commandToString(
|
||||
strobeCommand.getCommand()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
sc_time WriteChecker::writeToWrite(ScheduledCommand& firstWrite, ScheduledCommand& secondWrite)
|
||||
sc_time WriteChecker::writeToWrite(ScheduledCommand &firstWrite,
|
||||
ScheduledCommand &secondWrite)
|
||||
{
|
||||
sc_assert(firstWrite.getCommand() == Command::Write || firstWrite.getCommand() == Command::WriteA);
|
||||
sc_assert(secondWrite.getCommand() == Command::Write || secondWrite.getCommand() == Command::WriteA);
|
||||
sc_assert(firstWrite.getCommand() == Command::Write
|
||||
|| firstWrite.getCommand() == Command::WriteA);
|
||||
sc_assert(secondWrite.getCommand() == Command::Write
|
||||
|| secondWrite.getCommand() == Command::WriteA);
|
||||
|
||||
MemSpec& config = Configuration::getInstance().memSpec;
|
||||
sc_time tCCD = (firstWrite.getBankGroup() == secondWrite.getBankGroup()) ? config.tCCD_L : config.tCCD_S;
|
||||
return max(tCCD, getWriteAccessTime());
|
||||
MemSpec &config = Configuration::getInstance().memSpec;
|
||||
sc_time tCCD = (firstWrite.getBankGroup() == secondWrite.getBankGroup()) ?
|
||||
config.tCCD_L : config.tCCD_S;
|
||||
return max(tCCD, getWriteAccessTime());
|
||||
}
|
||||
|
||||
sc_time WriteChecker::readToWrite(ScheduledCommand& read __attribute__((unused)), ScheduledCommand& write __attribute__((unused)))
|
||||
sc_time WriteChecker::readToWrite(ScheduledCommand &read __attribute__((
|
||||
unused)), ScheduledCommand &write __attribute__((unused)))
|
||||
{
|
||||
sc_assert(read.getCommand() == Command::Read || read.getCommand() == Command::ReadA);
|
||||
sc_assert(write.getCommand() == Command::Write || write.getCommand() == Command::WriteA);
|
||||
sc_assert(read.getCommand() == Command::Read
|
||||
|| read.getCommand() == Command::ReadA);
|
||||
sc_assert(write.getCommand() == Command::Write
|
||||
|| write.getCommand() == Command::WriteA);
|
||||
|
||||
MemSpec& config = Configuration::getInstance().memSpec;
|
||||
return config.tRL + getReadAccessTime() - config.tWL + config.clk * 2;
|
||||
MemSpec &config = Configuration::getInstance().memSpec;
|
||||
return config.tRL + getReadAccessTime() - config.tWL + config.clk * 2;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,18 +45,22 @@
|
||||
class WriteChecker: public ICommandChecker
|
||||
{
|
||||
public:
|
||||
WriteChecker(const Configuration& config, ControllerState& state) : config(config), state(state) {}
|
||||
virtual ~WriteChecker() {}
|
||||
WriteChecker(const Configuration &config,
|
||||
ControllerState &state) : config(config), state(state) {}
|
||||
virtual ~WriteChecker() {}
|
||||
|
||||
virtual void delayToSatisfyConstraints(ScheduledCommand& command) const override;
|
||||
virtual void delayToSatisfyConstraints(ScheduledCommand &command) const
|
||||
override;
|
||||
|
||||
static sc_time writeToWrite(ScheduledCommand& firstWrite, ScheduledCommand& secondWrite);
|
||||
static sc_time readToWrite(ScheduledCommand& read, ScheduledCommand& write);
|
||||
static sc_time writeToWrite(ScheduledCommand &firstWrite,
|
||||
ScheduledCommand &secondWrite);
|
||||
static sc_time readToWrite(ScheduledCommand &read, ScheduledCommand &write);
|
||||
private:
|
||||
bool collidesOnDataStrobe(ScheduledCommand& write) const;
|
||||
bool collidesWithStrobeCommand(ScheduledCommand& write, ScheduledCommand& strobeCommand) const;
|
||||
const Configuration& config;
|
||||
ControllerState& state;
|
||||
bool collidesOnDataStrobe(ScheduledCommand &write) const;
|
||||
bool collidesWithStrobeCommand(ScheduledCommand &write,
|
||||
ScheduledCommand &strobeCommand) const;
|
||||
const Configuration &config;
|
||||
ControllerState &state;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -38,31 +38,30 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
void Fifo::schedule(gp* payload)
|
||||
void Fifo::schedule(gp *payload)
|
||||
{
|
||||
buffer[DramExtension::getExtension(payload).getBank()].emplace_back(payload);
|
||||
}
|
||||
|
||||
pair<Command, tlm::tlm_generic_payload*> Fifo::getNextRequest(Bank bank)
|
||||
pair<Command, tlm::tlm_generic_payload *> Fifo::getNextRequest(Bank bank)
|
||||
{
|
||||
if(!buffer[bank].empty())
|
||||
{
|
||||
gp* payload = buffer[bank].front();
|
||||
if (!buffer[bank].empty()) {
|
||||
gp *payload = buffer[bank].front();
|
||||
Command command = IScheduler::getNextCommand(*payload);
|
||||
if(command == Command::Read || command == Command::ReadA || command == Command::Write || command == Command::WriteA)
|
||||
{
|
||||
if (command == Command::Read || command == Command::ReadA
|
||||
|| command == Command::Write || command == Command::WriteA) {
|
||||
buffer[bank].pop_front();
|
||||
}
|
||||
|
||||
return pair<Command, tlm::tlm_generic_payload*>(command, payload);
|
||||
return pair<Command, tlm::tlm_generic_payload *>(command, payload);
|
||||
}
|
||||
|
||||
return pair<Command, tlm::tlm_generic_payload*>(Command::NOP, NULL);
|
||||
return pair<Command, tlm::tlm_generic_payload *>(Command::NOP, NULL);
|
||||
}
|
||||
|
||||
gp* Fifo::getPendingRequest(Bank /*bank*/)
|
||||
gp *Fifo::getPendingRequest(Bank /*bank*/)
|
||||
{
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -50,12 +50,13 @@ public:
|
||||
Fifo(ControllerCore &controllerCore) : IScheduler(controllerCore) {}
|
||||
virtual ~Fifo() {}
|
||||
|
||||
void schedule(gp* payload) override;
|
||||
std::pair<Command, tlm::tlm_generic_payload*> getNextRequest(Bank bank) override;
|
||||
virtual gp* getPendingRequest(Bank bank) override;
|
||||
void schedule(gp *payload) override;
|
||||
std::pair<Command, tlm::tlm_generic_payload *> getNextRequest(
|
||||
Bank bank) override;
|
||||
virtual gp *getPendingRequest(Bank bank) override;
|
||||
|
||||
private:
|
||||
std::map<Bank, std::deque<gp*>> buffer;
|
||||
std::map<Bank, std::deque<gp *>> buffer;
|
||||
};
|
||||
|
||||
#endif /* FIFO_H_ */
|
||||
|
||||
@@ -44,7 +44,8 @@ void FifoStrict::schedule(tlm::tlm_generic_payload *payload)
|
||||
buffer.push_back(std::pair<Bank, tlm::tlm_generic_payload *>(bank, payload));
|
||||
}
|
||||
|
||||
std::pair<Command, tlm::tlm_generic_payload *> FifoStrict::getNextRequest(Bank bank)
|
||||
std::pair<Command, tlm::tlm_generic_payload *> FifoStrict::getNextRequest(
|
||||
Bank bank)
|
||||
{
|
||||
if (!buffer.empty()) {
|
||||
|
||||
@@ -76,7 +77,7 @@ std::pair<Command, tlm::tlm_generic_payload *> FifoStrict::getNextRequest(Bank b
|
||||
//
|
||||
Command command = IScheduler::getNextCommand(*payload);
|
||||
|
||||
if(commandIsIn(command, {Command::Read, Command::Write, Command::ReadA, Command::WriteA})) {
|
||||
if (commandIsIn(command, {Command::Read, Command::Write, Command::ReadA, Command::WriteA})) {
|
||||
buffer.pop_front();
|
||||
|
||||
// Check if the next transaction is a blocked read or write
|
||||
@@ -91,7 +92,7 @@ std::pair<Command, tlm::tlm_generic_payload *> FifoStrict::getNextRequest(Bank b
|
||||
}
|
||||
}
|
||||
|
||||
return pair<Command, tlm::tlm_generic_payload*>(command, payload);
|
||||
return pair<Command, tlm::tlm_generic_payload *>(command, payload);
|
||||
|
||||
} else {
|
||||
// The next request in the FIFO is NOT for the bank passed as parameter.
|
||||
@@ -115,20 +116,21 @@ std::pair<Command, tlm::tlm_generic_payload *> FifoStrict::getNextRequest(Bank b
|
||||
// the next command for this request is read or write
|
||||
// NOP will be returned and no operation will be
|
||||
// performed.
|
||||
return pair<Command, tlm::tlm_generic_payload*>(Command::NOP, NULL);
|
||||
} else {
|
||||
return pair<Command, tlm::tlm_generic_payload *>(Command::NOP, NULL);
|
||||
}
|
||||
else {
|
||||
// Commands other than read and write are issued normally.
|
||||
return pair<Command, tlm::tlm_generic_payload*>(command, payload);
|
||||
return pair<Command, tlm::tlm_generic_payload *>(command, payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pair<Command, tlm::tlm_generic_payload*>(Command::NOP, NULL);
|
||||
return pair<Command, tlm::tlm_generic_payload *>(Command::NOP, NULL);
|
||||
}
|
||||
|
||||
gp* FifoStrict::getPendingRequest(Bank /*bank*/)
|
||||
gp *FifoStrict::getPendingRequest(Bank /*bank*/)
|
||||
{
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -51,12 +51,15 @@ class FifoStrict : public IScheduler
|
||||
{
|
||||
public:
|
||||
IController &controller;
|
||||
FifoStrict(IController &controller, ControllerCore &controllerCore) : IScheduler(controllerCore), controller(controller) {}
|
||||
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;
|
||||
virtual gp* getPendingRequest(Bank bank) override;
|
||||
void schedule(gp *payload) override;
|
||||
std::pair<Command, tlm::tlm_generic_payload *> getNextRequest(
|
||||
Bank bank) override;
|
||||
virtual gp *getPendingRequest(Bank bank) override;
|
||||
|
||||
private:
|
||||
std::deque<std::pair<Bank, tlm::tlm_generic_payload *>> buffer;
|
||||
|
||||
@@ -65,32 +65,30 @@ void FR_FCFS::schedule(gp *payload)
|
||||
// should provide a true or false when the placement into the buffer worked
|
||||
// out or not (?).
|
||||
buffer[DramExtension::getExtension(payload).getBank()]
|
||||
.emplace_back(payload);
|
||||
.emplace_back(payload);
|
||||
}
|
||||
|
||||
std::pair<Command, gp*> FR_FCFS::getNextRequest(Bank bank)
|
||||
std::pair<Command, gp *> FR_FCFS::getNextRequest(Bank bank)
|
||||
{
|
||||
// If the bank is empty like Bank0 in the example we do nothing
|
||||
if(buffer[bank].empty())
|
||||
{
|
||||
return pair<Command, tlm::tlm_generic_payload*>(Command::NOP, NULL);
|
||||
if (buffer[bank].empty()) {
|
||||
return pair<Command, tlm::tlm_generic_payload *>(Command::NOP, NULL);
|
||||
}
|
||||
|
||||
// In FR_FCFS row hits have always the highest priority, therefore we search
|
||||
// for row hits. If we find a row hit, we remove the transaction from the
|
||||
// queue and send it to the DRAM.
|
||||
deque<gp*>::iterator it = FindRowHit(bank);
|
||||
if(it != buffer[bank].end())
|
||||
{
|
||||
gp* payload = *it;
|
||||
deque<gp *>::iterator it = FindRowHit(bank);
|
||||
if (it != buffer[bank].end()) {
|
||||
gp *payload = *it;
|
||||
buffer[bank].erase(it);
|
||||
return pair<Command, gp*>(getReadWriteCommand(*payload), payload);
|
||||
return pair<Command, gp *>(getReadWriteCommand(*payload), payload);
|
||||
}
|
||||
|
||||
// If there is no row hit, the FR_FCFS takes always the oldest transaction
|
||||
// in the buffer, i.e. the transaction in the front.
|
||||
return pair<Command, gp*>(getNextCommand(buffer[bank].front()),
|
||||
buffer[bank].front());
|
||||
return pair<Command, gp *>(getNextCommand(buffer[bank].front()),
|
||||
buffer[bank].front());
|
||||
}
|
||||
|
||||
// This function searches for a row hit in the scheduling queue of the specific
|
||||
@@ -100,21 +98,19 @@ std::pair<Command, gp*> FR_FCFS::getNextRequest(Bank bank)
|
||||
// deque container. The past-the-end element is the theoretical element that
|
||||
// would follow the last element in the deque container. It does not point to
|
||||
// any element, and thus shall not be dereferenced.
|
||||
deque<gp*>::iterator FR_FCFS::FindRowHit(Bank bank)
|
||||
deque<gp *>::iterator FR_FCFS::FindRowHit(Bank bank)
|
||||
{
|
||||
deque<gp*> &queue = buffer[bank];
|
||||
deque<gp *> &queue = buffer[bank];
|
||||
|
||||
if(!controllerCore.getRowBufferStates().rowBufferIsOpen(bank))
|
||||
if (!controllerCore.getRowBufferStates().rowBufferIsOpen(bank))
|
||||
return queue.end();
|
||||
|
||||
// Traverse the scheduling queue of the specific bank:
|
||||
for(auto it = queue.begin(); it!=queue.end(); it++)
|
||||
{
|
||||
gp* payload = *it;
|
||||
for (auto it = queue.begin(); it != queue.end(); it++) {
|
||||
gp *payload = *it;
|
||||
//Found row-hit and return the according iterator
|
||||
if(DramExtension::getRow(payload)
|
||||
== controllerCore.getRowBufferStates().getRowInRowBuffer(bank))
|
||||
{
|
||||
if (DramExtension::getRow(payload)
|
||||
== controllerCore.getRowBufferStates().getRowInRowBuffer(bank)) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
@@ -122,7 +118,7 @@ deque<gp*>::iterator FR_FCFS::FindRowHit(Bank bank)
|
||||
return queue.end();
|
||||
}
|
||||
|
||||
gp* FR_FCFS::getPendingRequest(Bank /*bank*/)
|
||||
gp *FR_FCFS::getPendingRequest(Bank /*bank*/)
|
||||
{
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -48,16 +48,17 @@
|
||||
class FR_FCFS : public IScheduler
|
||||
{
|
||||
public:
|
||||
FR_FCFS(ControllerCore &controllerCore) : IScheduler(controllerCore){}
|
||||
virtual ~FR_FCFS(){}
|
||||
FR_FCFS(ControllerCore &controllerCore) : IScheduler(controllerCore) {}
|
||||
virtual ~FR_FCFS() {}
|
||||
|
||||
void schedule(gp* payload) override;
|
||||
std::pair<Command, tlm::tlm_generic_payload*> getNextRequest(Bank bank) override;
|
||||
virtual gp* getPendingRequest(Bank bank) override;
|
||||
void schedule(gp *payload) override;
|
||||
std::pair<Command, tlm::tlm_generic_payload *> getNextRequest(
|
||||
Bank bank) override;
|
||||
virtual gp *getPendingRequest(Bank bank) override;
|
||||
|
||||
protected:
|
||||
std::map<Bank, std::deque<gp*>> buffer;
|
||||
std::deque<gp*>::iterator FindRowHit(Bank bank);
|
||||
std::map<Bank, std::deque<gp *>> buffer;
|
||||
std::deque<gp *>::iterator FindRowHit(Bank bank);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -40,56 +40,43 @@
|
||||
// TODO: what is missed is a check if the buffers are full. This will only work
|
||||
// if we have buffers with a fixed size (Prado's future patch).
|
||||
|
||||
std::pair<Command, gp*> FR_FCFS_GRP::getNextRequest(Bank bank)
|
||||
std::pair<Command, gp *> FR_FCFS_GRP::getNextRequest(Bank bank)
|
||||
{
|
||||
// If the bank is empty we do nothing:
|
||||
if(buffer[bank].empty())
|
||||
{
|
||||
return pair<Command, tlm::tlm_generic_payload*>(Command::NOP, NULL);
|
||||
if (buffer[bank].empty()) {
|
||||
return pair<Command, tlm::tlm_generic_payload *>(Command::NOP, NULL);
|
||||
}
|
||||
|
||||
// If we are in write mode we should check if we should switch to read mode
|
||||
// because there are no writes anymore in the buffer.
|
||||
if(readMode == false)
|
||||
{
|
||||
if(getNumberOfRequest(tlm::TLM_WRITE_COMMAND) == 0)
|
||||
{
|
||||
if (readMode == false) {
|
||||
if (getNumberOfRequest(tlm::TLM_WRITE_COMMAND) == 0) {
|
||||
readMode = true;
|
||||
}
|
||||
}
|
||||
else // If we are in read mode but all reads are served we switch to write
|
||||
{
|
||||
if(getNumberOfRequest(tlm::TLM_READ_COMMAND) == 0)
|
||||
{
|
||||
} else { // If we are in read mode but all reads are served we switch to write
|
||||
if (getNumberOfRequest(tlm::TLM_READ_COMMAND) == 0) {
|
||||
readMode = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Now lets search for read and write commands. However keep in mind that
|
||||
// readMode is a shared variable for all the banks!
|
||||
if(readMode == true)
|
||||
{
|
||||
if (readMode == true) {
|
||||
// 1. Seach for read hit:
|
||||
for(auto it = buffer[bank].begin(); it!=buffer[bank].end(); it++)
|
||||
{
|
||||
gp* read = *it;
|
||||
for (auto it = buffer[bank].begin(); it != buffer[bank].end(); it++) {
|
||||
gp *read = *it;
|
||||
|
||||
if(read->get_command() == tlm::TLM_READ_COMMAND)
|
||||
{
|
||||
if (read->get_command() == tlm::TLM_READ_COMMAND) {
|
||||
// If there is a row hit:
|
||||
if(DramExtension::getRow(read)
|
||||
== controllerCore.getRowBufferStates()
|
||||
.getRowInRowBuffer(bank))
|
||||
{
|
||||
if(hazardDetection(bank, it) == false)
|
||||
{
|
||||
if (DramExtension::getRow(read)
|
||||
== controllerCore.getRowBufferStates()
|
||||
.getRowInRowBuffer(bank)) {
|
||||
if (hazardDetection(bank, it) == false) {
|
||||
buffer[bank].erase(it);
|
||||
printDebugMessage("Read Hit found");
|
||||
return pair<Command, gp*>(getReadWriteCommand(*read),
|
||||
read);
|
||||
}
|
||||
else
|
||||
{
|
||||
return pair<Command, gp *>(getReadWriteCommand(*read),
|
||||
read);
|
||||
} else {
|
||||
// If there was a hazard, switch the mode and try again:
|
||||
readMode = false;
|
||||
return getNextRequest(bank);
|
||||
@@ -99,68 +86,55 @@ std::pair<Command, gp*> FR_FCFS_GRP::getNextRequest(Bank bank)
|
||||
}
|
||||
|
||||
// 2. Search for read miss:
|
||||
for(auto it = buffer[bank].begin(); it!=buffer[bank].end(); it++)
|
||||
{
|
||||
gp* read = *it;
|
||||
for (auto it = buffer[bank].begin(); it != buffer[bank].end(); it++) {
|
||||
gp *read = *it;
|
||||
|
||||
if(read->get_command() == tlm::TLM_READ_COMMAND)
|
||||
{
|
||||
if(hazardDetection(bank, it) == false)
|
||||
{
|
||||
if (read->get_command() == tlm::TLM_READ_COMMAND) {
|
||||
if (hazardDetection(bank, it) == false) {
|
||||
printDebugMessage("Read miss found");
|
||||
return pair<Command, gp*>(getNextCommand(read),read);
|
||||
}
|
||||
else
|
||||
{
|
||||
return pair<Command, gp *>(getNextCommand(read), read);
|
||||
} else {
|
||||
// If there was a hazard, switch the mode and try again:
|
||||
readMode = false;
|
||||
return getNextRequest(bank);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else // write mode:
|
||||
{
|
||||
} else { // write mode:
|
||||
// 3. Search for write hit:
|
||||
for(auto it = buffer[bank].begin(); it!=buffer[bank].end(); it++)
|
||||
{
|
||||
gp* write = *it;
|
||||
for (auto it = buffer[bank].begin(); it != buffer[bank].end(); it++) {
|
||||
gp *write = *it;
|
||||
|
||||
if(write->get_command() == tlm::TLM_WRITE_COMMAND)
|
||||
{
|
||||
if (write->get_command() == tlm::TLM_WRITE_COMMAND) {
|
||||
// If there is a row hit:
|
||||
if(DramExtension::getRow(write)
|
||||
if (DramExtension::getRow(write)
|
||||
== controllerCore.getRowBufferStates()
|
||||
.getRowInRowBuffer(bank))
|
||||
{
|
||||
.getRowInRowBuffer(bank)) {
|
||||
buffer[bank].erase(it);
|
||||
printDebugMessage("Write Hit found");
|
||||
return pair<Command, gp*>(getReadWriteCommand(*write),
|
||||
write);
|
||||
return pair<Command, gp *>(getReadWriteCommand(*write),
|
||||
write);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Search for write miss:
|
||||
for(auto it = buffer[bank].begin(); it!=buffer[bank].end(); it++)
|
||||
{
|
||||
gp* write = *it;
|
||||
for (auto it = buffer[bank].begin(); it != buffer[bank].end(); it++) {
|
||||
gp *write = *it;
|
||||
|
||||
if(write->get_command() == tlm::TLM_WRITE_COMMAND)
|
||||
{
|
||||
if (write->get_command() == tlm::TLM_WRITE_COMMAND) {
|
||||
printDebugMessage("Write miss found");
|
||||
return pair<Command, gp*>(getNextCommand(write),write);
|
||||
return pair<Command, gp *>(getNextCommand(write), write);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If nothing was found we check the other banks before we switch the mode:
|
||||
pair<Command, gp*> other(Command::NOP, NULL);
|
||||
pair<Command, gp *> other(Command::NOP, NULL);
|
||||
unsigned int B = Configuration::getInstance().memSpec.NumberOfBanks;
|
||||
|
||||
for(unsigned int i=1; i<B; i++)
|
||||
{
|
||||
Bank nextBank((bank.ID()+i) % B);
|
||||
for (unsigned int i = 1; i < B; i++) {
|
||||
Bank nextBank((bank.ID() + i) % B);
|
||||
ctrl->scheduleNextFromScheduler(nextBank);
|
||||
}
|
||||
|
||||
@@ -175,21 +149,18 @@ std::pair<Command, gp*> FR_FCFS_GRP::getNextRequest(Bank bank)
|
||||
|
||||
// There is a hazard if a read is found which will be scheduled before a write
|
||||
// to the same column and the same row of the same bank:
|
||||
bool FR_FCFS_GRP::hazardDetection(Bank bank, std::deque<gp*>::iterator ext)
|
||||
bool FR_FCFS_GRP::hazardDetection(Bank bank, std::deque<gp *>::iterator ext)
|
||||
{
|
||||
gp* read = *ext;
|
||||
gp *read = *ext;
|
||||
|
||||
//for(unsigned long i=0; i < id; i++)
|
||||
for(auto it = buffer[bank].begin(); it!=ext; it++)
|
||||
{
|
||||
gp* write = *it;
|
||||
if(write->get_command() == tlm::TLM_WRITE_COMMAND)
|
||||
{
|
||||
if((DramExtension::getExtension(read).getColumn()
|
||||
== DramExtension::getExtension(write).getColumn())
|
||||
&& (DramExtension::getExtension(read).getRow()
|
||||
== DramExtension::getExtension(write).getRow()))
|
||||
{
|
||||
for (auto it = buffer[bank].begin(); it != ext; it++) {
|
||||
gp *write = *it;
|
||||
if (write->get_command() == tlm::TLM_WRITE_COMMAND) {
|
||||
if ((DramExtension::getExtension(read).getColumn()
|
||||
== DramExtension::getExtension(write).getColumn())
|
||||
&& (DramExtension::getExtension(read).getRow()
|
||||
== DramExtension::getExtension(write).getRow())) {
|
||||
printDebugMessage("Hazard Detected");
|
||||
return true;
|
||||
}
|
||||
@@ -202,15 +173,12 @@ bool FR_FCFS_GRP::hazardDetection(Bank bank, std::deque<gp*>::iterator ext)
|
||||
unsigned int FR_FCFS_GRP::getNumberOfRequest(tlm::tlm_command cmd)
|
||||
{
|
||||
unsigned int numberOfRequests = 0;
|
||||
for(unsigned int i = 0;
|
||||
i < Configuration::getInstance().memSpec.NumberOfBanks;
|
||||
i++)
|
||||
{
|
||||
for(auto it = buffer[i].begin(); it!=buffer[i].end(); it++)
|
||||
{
|
||||
gp* trans = *it;
|
||||
if(trans->get_command()==cmd)
|
||||
{
|
||||
for (unsigned int i = 0;
|
||||
i < Configuration::getInstance().memSpec.NumberOfBanks;
|
||||
i++) {
|
||||
for (auto it = buffer[i].begin(); it != buffer[i].end(); it++) {
|
||||
gp *trans = *it;
|
||||
if (trans->get_command() == cmd) {
|
||||
numberOfRequests++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,20 +44,20 @@ class Controller;
|
||||
class FR_FCFS_GRP : public FR_FCFS
|
||||
{
|
||||
public:
|
||||
FR_FCFS_GRP(ControllerCore &controllerCore, Controller * c) :
|
||||
FR_FCFS_GRP(ControllerCore &controllerCore, Controller *c) :
|
||||
FR_FCFS(controllerCore),
|
||||
ctrl(c),
|
||||
readMode(true)
|
||||
{
|
||||
}
|
||||
|
||||
std::pair<Command, tlm::tlm_generic_payload*>
|
||||
getNextRequest(Bank bank) override;
|
||||
std::pair<Command, tlm::tlm_generic_payload *>
|
||||
getNextRequest(Bank bank) override;
|
||||
|
||||
private:
|
||||
|
||||
Controller * ctrl;
|
||||
bool hazardDetection(Bank bank, std::deque<gp*>::iterator ext);
|
||||
Controller *ctrl;
|
||||
bool hazardDetection(Bank bank, std::deque<gp *>::iterator ext);
|
||||
unsigned int getNumberOfRequest(tlm::tlm_command cmd);
|
||||
void printDebugMessage(std::string message);
|
||||
bool readMode;
|
||||
|
||||
@@ -38,12 +38,11 @@
|
||||
// The FR_FCFS_Read_Priority works exactly like the FR_FCFS but reads are
|
||||
// prioratized over writes. For detailed documentation look into the FR_FCFS.
|
||||
|
||||
std::pair<Command, gp*> FR_FCFS_RP::getNextRequest(Bank bank)
|
||||
std::pair<Command, gp *> FR_FCFS_RP::getNextRequest(Bank bank)
|
||||
{
|
||||
// If the bank is empty like Bank0 in the example we do nothing:
|
||||
if(buffer[bank].empty())
|
||||
{
|
||||
return pair<Command, tlm::tlm_generic_payload*>(Command::NOP, NULL);
|
||||
if (buffer[bank].empty()) {
|
||||
return pair<Command, tlm::tlm_generic_payload *>(Command::NOP, NULL);
|
||||
}
|
||||
|
||||
// Order of Priority:
|
||||
@@ -53,40 +52,33 @@ std::pair<Command, gp*> FR_FCFS_RP::getNextRequest(Bank bank)
|
||||
// 4. Write Miss
|
||||
|
||||
// 1. Seach for read hit:
|
||||
for(auto it = buffer[bank].begin(); it!=buffer[bank].end(); it++)
|
||||
{
|
||||
gp* read = *it;
|
||||
for (auto it = buffer[bank].begin(); it != buffer[bank].end(); it++) {
|
||||
gp *read = *it;
|
||||
|
||||
if(read->get_command() == tlm::TLM_READ_COMMAND)
|
||||
{
|
||||
if (read->get_command() == tlm::TLM_READ_COMMAND) {
|
||||
// If there is a row hit:
|
||||
if(DramExtension::getRow(read)
|
||||
== controllerCore.getRowBufferStates().getRowInRowBuffer(bank))
|
||||
{
|
||||
if(hazardDetection(bank, it) == false)
|
||||
{
|
||||
if (DramExtension::getRow(read)
|
||||
== controllerCore.getRowBufferStates().getRowInRowBuffer(bank)) {
|
||||
if (hazardDetection(bank, it) == false) {
|
||||
buffer[bank].erase(it);
|
||||
printDebugMessage("Read Hit found");
|
||||
return pair<Command, gp*>(getReadWriteCommand(*read),read);
|
||||
return pair<Command, gp *>(getReadWriteCommand(*read), read);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Search for write hit:
|
||||
for(auto it = buffer[bank].begin(); it!=buffer[bank].end(); it++)
|
||||
{
|
||||
gp* write = *it;
|
||||
for (auto it = buffer[bank].begin(); it != buffer[bank].end(); it++) {
|
||||
gp *write = *it;
|
||||
|
||||
if(write->get_command() == tlm::TLM_WRITE_COMMAND)
|
||||
{
|
||||
if (write->get_command() == tlm::TLM_WRITE_COMMAND) {
|
||||
// If there is a row hit:
|
||||
if(DramExtension::getRow(write)
|
||||
== controllerCore.getRowBufferStates().getRowInRowBuffer(bank))
|
||||
{
|
||||
if (DramExtension::getRow(write)
|
||||
== controllerCore.getRowBufferStates().getRowInRowBuffer(bank)) {
|
||||
buffer[bank].erase(it);
|
||||
printDebugMessage("Write Hit found");
|
||||
return pair<Command, gp*>(getReadWriteCommand(*write),write);
|
||||
return pair<Command, gp *>(getReadWriteCommand(*write), write);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,52 +86,45 @@ std::pair<Command, gp*> FR_FCFS_RP::getNextRequest(Bank bank)
|
||||
// For now return the oldest request but prefere also reads before writes:
|
||||
|
||||
// 3. Search for read miss:
|
||||
for(auto it = buffer[bank].begin(); it!=buffer[bank].end(); it++)
|
||||
{
|
||||
gp* read = *it;
|
||||
for (auto it = buffer[bank].begin(); it != buffer[bank].end(); it++) {
|
||||
gp *read = *it;
|
||||
|
||||
if(read->get_command() == tlm::TLM_READ_COMMAND)
|
||||
{
|
||||
if(hazardDetection(bank, it) == false)
|
||||
{
|
||||
if (read->get_command() == tlm::TLM_READ_COMMAND) {
|
||||
if (hazardDetection(bank, it) == false) {
|
||||
printDebugMessage("Read miss found");
|
||||
return pair<Command, gp*>(getNextCommand(read),read);
|
||||
return pair<Command, gp *>(getNextCommand(read), read);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Search for write miss:
|
||||
for(auto it = buffer[bank].begin(); it!=buffer[bank].end(); it++)
|
||||
{
|
||||
gp* write = *it;
|
||||
for (auto it = buffer[bank].begin(); it != buffer[bank].end(); it++) {
|
||||
gp *write = *it;
|
||||
|
||||
if(write->get_command() == tlm::TLM_WRITE_COMMAND)
|
||||
{
|
||||
if (write->get_command() == tlm::TLM_WRITE_COMMAND) {
|
||||
printDebugMessage("Write miss found");
|
||||
return pair<Command, gp*>(getNextCommand(write),write);
|
||||
return pair<Command, gp *>(getNextCommand(write), write);
|
||||
}
|
||||
}
|
||||
|
||||
reportFatal("FR_FCFS_RP", "Never should go here ...");
|
||||
return pair<Command, tlm::tlm_generic_payload *>(Command::NOP, NULL);
|
||||
}
|
||||
|
||||
// There is a hazard if a read is found which will be scheduled before a write
|
||||
// to the same column and the same row of the same bank:
|
||||
bool FR_FCFS_RP::hazardDetection(Bank bank, std::deque<gp*>::iterator ext)
|
||||
bool FR_FCFS_RP::hazardDetection(Bank bank, std::deque<gp *>::iterator ext)
|
||||
{
|
||||
gp* read = *ext;
|
||||
gp *read = *ext;
|
||||
|
||||
//for(unsigned long i=0; i < id; i++)
|
||||
for(auto it = buffer[bank].begin(); it!=ext; it++)
|
||||
{
|
||||
gp* write = *it;
|
||||
if(write->get_command() == tlm::TLM_WRITE_COMMAND)
|
||||
{
|
||||
if((DramExtension::getExtension(read).getColumn()
|
||||
== DramExtension::getExtension(write).getColumn())
|
||||
&& (DramExtension::getExtension(read).getRow()
|
||||
== DramExtension::getExtension(write).getRow()))
|
||||
{
|
||||
for (auto it = buffer[bank].begin(); it != ext; it++) {
|
||||
gp *write = *it;
|
||||
if (write->get_command() == tlm::TLM_WRITE_COMMAND) {
|
||||
if ((DramExtension::getExtension(read).getColumn()
|
||||
== DramExtension::getExtension(write).getColumn())
|
||||
&& (DramExtension::getExtension(read).getRow()
|
||||
== DramExtension::getExtension(write).getRow())) {
|
||||
printDebugMessage("Hazard Detected");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -43,12 +43,12 @@ class FR_FCFS_RP : public FR_FCFS
|
||||
public:
|
||||
FR_FCFS_RP(ControllerCore &controllerCore) : FR_FCFS(controllerCore) {}
|
||||
|
||||
std::pair<Command, tlm::tlm_generic_payload*>
|
||||
getNextRequest(Bank bank) override;
|
||||
std::pair<Command, tlm::tlm_generic_payload *>
|
||||
getNextRequest(Bank bank) override;
|
||||
|
||||
private:
|
||||
|
||||
bool hazardDetection(Bank bank, std::deque<gp*>::iterator ext);
|
||||
bool hazardDetection(Bank bank, std::deque<gp *>::iterator ext);
|
||||
void printDebugMessage(std::string message);
|
||||
};
|
||||
|
||||
|
||||
@@ -47,20 +47,16 @@ void IScheduler::printDebugMessage(std::string message)
|
||||
}
|
||||
|
||||
// Get the next command that is necessary to process the request representend by the payload
|
||||
Command IScheduler::getNextCommand(gp& payload)
|
||||
Command IScheduler::getNextCommand(gp &payload)
|
||||
{
|
||||
Bank bank = DramExtension::getBank(payload);
|
||||
if(!controllerCore.getRowBufferStates().rowBufferIsOpen(bank))
|
||||
{
|
||||
if (!controllerCore.getRowBufferStates().rowBufferIsOpen(bank)) {
|
||||
return Command::Activate;
|
||||
}
|
||||
else if(controllerCore.getRowBufferStates().rowBufferIsOpen(bank) &&
|
||||
controllerCore.getRowBufferStates().getRowInRowBuffer(bank) != DramExtension::getRow(payload))
|
||||
{
|
||||
} else if (controllerCore.getRowBufferStates().rowBufferIsOpen(bank) &&
|
||||
controllerCore.getRowBufferStates().getRowInRowBuffer(bank) !=
|
||||
DramExtension::getRow(payload)) {
|
||||
return Command::Precharge;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return getReadWriteCommand(payload);
|
||||
}
|
||||
}
|
||||
@@ -70,19 +66,16 @@ Command IScheduler::getNextCommand(gp *payload)
|
||||
return getNextCommand(*payload);
|
||||
}
|
||||
|
||||
Command IScheduler::getReadWriteCommand(gp& payload)
|
||||
Command IScheduler::getReadWriteCommand(gp &payload)
|
||||
{
|
||||
|
||||
if (payload.get_command() == tlm::TLM_READ_COMMAND)
|
||||
{
|
||||
if(Configuration::getInstance().OpenPagePolicy)
|
||||
if (payload.get_command() == tlm::TLM_READ_COMMAND) {
|
||||
if (Configuration::getInstance().OpenPagePolicy)
|
||||
return Command::Read;
|
||||
else
|
||||
return Command::ReadA;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(Configuration::getInstance().OpenPagePolicy)
|
||||
} else {
|
||||
if (Configuration::getInstance().OpenPagePolicy)
|
||||
return Command::Write;
|
||||
else
|
||||
return Command::WriteA;
|
||||
|
||||
@@ -49,12 +49,12 @@ typedef tlm::tlm_generic_payload gp;
|
||||
class IScheduler
|
||||
{
|
||||
public:
|
||||
virtual ~IScheduler(){}
|
||||
IScheduler(ControllerCore &controllerCore) : controllerCore(controllerCore){}
|
||||
virtual ~IScheduler() {}
|
||||
IScheduler(ControllerCore &controllerCore) : controllerCore(controllerCore) {}
|
||||
|
||||
virtual void schedule(gp* payload) = 0;
|
||||
virtual std::pair<Command, gp*> getNextRequest(Bank bank) = 0;
|
||||
virtual gp* getPendingRequest(Bank bank) = 0;
|
||||
virtual void schedule(gp *payload) = 0;
|
||||
virtual std::pair<Command, gp *> getNextRequest(Bank bank) = 0;
|
||||
virtual gp *getPendingRequest(Bank bank) = 0;
|
||||
static std::string sendername;
|
||||
|
||||
protected:
|
||||
|
||||
@@ -22,27 +22,25 @@ void SMS::schedule(gp *payload)
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<Command, gp*> SMS::getNextRequest(Bank bank)
|
||||
std::pair<Command, gp *> SMS::getNextRequest(Bank bank)
|
||||
{
|
||||
if (bankBuffers[bank].empty())
|
||||
{
|
||||
if (bankBuffers[bank].empty()) {
|
||||
debugManager.printDebugMessage(name(),
|
||||
"Get next request on bank " + to_string(bank.ID()) + " : EMPTY buffer");
|
||||
return pair<Command, tlm::tlm_generic_payload*>(Command::NOP, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
gp* payload = bankBuffers[bank].front();
|
||||
return pair<Command, tlm::tlm_generic_payload *>(Command::NOP, NULL);
|
||||
} else {
|
||||
gp *payload = bankBuffers[bank].front();
|
||||
Command command = IScheduler::getNextCommand(*payload);
|
||||
if (command == Command::Read || command == Command::ReadA || command == Command::Write
|
||||
|| command == Command::WriteA)
|
||||
{
|
||||
if (command == Command::Read || command == Command::ReadA
|
||||
|| command == Command::Write
|
||||
|| command == Command::WriteA) {
|
||||
inFlightMemRequestCounter[DramExtension::getExtension(payload).getThread()]--;
|
||||
bankBuffers[bank].pop_front();
|
||||
}
|
||||
|
||||
debugManager.printDebugMessage(name(), "Get next request on bank " + to_string(bank.ID()));
|
||||
return pair<Command, tlm::tlm_generic_payload*>(command, payload);
|
||||
debugManager.printDebugMessage(name(),
|
||||
"Get next request on bank " + to_string(bank.ID()));
|
||||
return pair<Command, tlm::tlm_generic_payload *>(command, payload);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,15 +50,15 @@ void SMS::batchScheduler()
|
||||
std::default_random_engine generator;
|
||||
std::bernoulli_distribution distribution((double) SJFprobability / 100.0);
|
||||
|
||||
while (true)
|
||||
{
|
||||
while (true) {
|
||||
updateMPKCs(memClk);
|
||||
if (isRequestBuffersEmpty()) {
|
||||
wait(newRequest);
|
||||
} else {
|
||||
multiBatchFormation(memClk);
|
||||
if (existReadyBatches()) {
|
||||
if (!isSystemLightlyLoaded() && (existLowIntensityThread() || distribution(generator))) {
|
||||
if (!isSystemLightlyLoaded() && (existLowIntensityThread()
|
||||
|| distribution(generator))) {
|
||||
pickSJF();
|
||||
} else {
|
||||
pickRR();
|
||||
@@ -82,23 +80,18 @@ bool SMS::pickSJF()
|
||||
{
|
||||
// find threads with ready batches
|
||||
std::vector<Thread> threadsWithReadyBatches;
|
||||
for (const auto &each : readyBatchInclusiveEndLocs)
|
||||
{
|
||||
if (!each.second.empty())
|
||||
{
|
||||
for (const auto &each : readyBatchInclusiveEndLocs) {
|
||||
if (!each.second.empty()) {
|
||||
// marked as thread with non-empty request buffer
|
||||
threadsWithReadyBatches.push_back(each.first);
|
||||
}
|
||||
}
|
||||
|
||||
if (!threadsWithReadyBatches.empty())
|
||||
{
|
||||
if (!threadsWithReadyBatches.empty()) {
|
||||
// pick shortest-job thread among threads with non-empty request buffer
|
||||
Thread &minThread = threadsWithReadyBatches.front();
|
||||
for (const auto &thread : threadsWithReadyBatches)
|
||||
{
|
||||
if (inFlightMemRequestCounter[thread] < inFlightMemRequestCounter[minThread])
|
||||
{
|
||||
for (const auto &thread : threadsWithReadyBatches) {
|
||||
if (inFlightMemRequestCounter[thread] < inFlightMemRequestCounter[minThread]) {
|
||||
minThread = thread;
|
||||
}
|
||||
}
|
||||
@@ -108,9 +101,7 @@ bool SMS::pickSJF()
|
||||
debugManager.printDebugMessage(name(),
|
||||
"[SJF] Select ready batch of thread " + to_string(minThread.ID()));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -131,17 +122,16 @@ void SMS::drainOnePayloadFromReadybatch(const sc_time &memClk)
|
||||
const size_t &inclusiveEndLoc = lastSelectedThread->second.front();
|
||||
assert(inclusiveEndLoc < requestBuffers.size());
|
||||
|
||||
for (size_t i = 0; i <= inclusiveEndLoc; ++i)
|
||||
{
|
||||
for (size_t i = 0; i <= inclusiveEndLoc; ++i) {
|
||||
wait(memClk);
|
||||
Bank bank = DramExtension::getExtension(requestBuffers[selectedThread].front()).getBank();
|
||||
Bank bank = DramExtension::getExtension(
|
||||
requestBuffers[selectedThread].front()).getBank();
|
||||
bankBuffers[bank].emplace_back(requestBuffers[selectedThread].front());
|
||||
requestBuffers[selectedThread].pop_front();
|
||||
|
||||
// decrement inclusive end locations of ready batches
|
||||
// except this ready batch
|
||||
for (size_t i = 1; i < readyBatchInclusiveEndLocs[selectedThread].size(); ++i)
|
||||
{
|
||||
for (size_t i = 1; i < readyBatchInclusiveEndLocs[selectedThread].size(); ++i) {
|
||||
--readyBatchInclusiveEndLocs[selectedThread][i];
|
||||
}
|
||||
|
||||
@@ -160,18 +150,17 @@ void SMS::drainOnePayloadFromReadybatch(const sc_time &memClk)
|
||||
*/
|
||||
bool SMS::pickRR()
|
||||
{
|
||||
if (lastSelectedThread == readyBatchInclusiveEndLocs.end())
|
||||
{
|
||||
if (lastSelectedThread == readyBatchInclusiveEndLocs.end()) {
|
||||
lastSelectedThread = readyBatchInclusiveEndLocs.begin();
|
||||
if (!(*lastSelectedThread).second.empty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
std::map<Thread, std::deque<size_t>>::iterator savedOriginalNextSelectedThread = lastSelectedThread;
|
||||
std::map<Thread, std::deque<size_t>>::iterator savedOriginalNextSelectedThread =
|
||||
lastSelectedThread;
|
||||
|
||||
do
|
||||
{
|
||||
do {
|
||||
lastSelectedThread++;
|
||||
if (lastSelectedThread == readyBatchInclusiveEndLocs.end()) {
|
||||
lastSelectedThread = readyBatchInclusiveEndLocs.begin();
|
||||
@@ -182,11 +171,13 @@ bool SMS::pickRR()
|
||||
} while ((*lastSelectedThread).second.empty());
|
||||
|
||||
debugManager.printDebugMessage(name(),
|
||||
"[RR] Select ready batch of thread " + to_string((*lastSelectedThread).first.ID()));
|
||||
"[RR] Select ready batch of thread " + to_string((
|
||||
*lastSelectedThread).first.ID()));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SMS::isSystemLightlyLoaded() const {
|
||||
bool SMS::isSystemLightlyLoaded() const
|
||||
{
|
||||
unsigned int totalRequest = 0;
|
||||
for (const auto &bankBuffer : bankBuffers) {
|
||||
totalRequest += bankBuffer.second.size();
|
||||
@@ -194,7 +185,8 @@ bool SMS::isSystemLightlyLoaded() const {
|
||||
return (totalRequest <= LOW_SYSTEM_LOAD);
|
||||
}
|
||||
|
||||
bool SMS::existLowIntensityThread() const {
|
||||
bool SMS::existLowIntensityThread() const
|
||||
{
|
||||
for (const auto &mpkcPerThread : MPKCs) {
|
||||
if (mpkcPerThread.second < LOW_MPKC) {
|
||||
return true;
|
||||
@@ -203,12 +195,15 @@ bool SMS::existLowIntensityThread() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SMS::isThresholdAgeExceeded(const Thread &thread, sc_time const &memClk, size_t const &inclusiveBeginLoc, size_t const &exclusiveEndLoc) {
|
||||
bool SMS::isThresholdAgeExceeded(const Thread &thread, sc_time const &memClk,
|
||||
size_t const &inclusiveBeginLoc, size_t const &exclusiveEndLoc)
|
||||
{
|
||||
assert((exclusiveEndLoc - inclusiveBeginLoc) >= 1);
|
||||
// find the oldest request in the thread's batch
|
||||
sc_time oldestGenerationTime = sc_time_stamp();
|
||||
for (size_t i = inclusiveBeginLoc; i != exclusiveEndLoc; ++i) {
|
||||
sc_time reqGenerationTime = GenerationExtension::getExtension(requestBuffers[thread][i]).TimeOfGeneration();
|
||||
sc_time reqGenerationTime = GenerationExtension::getExtension(
|
||||
requestBuffers[thread][i]).TimeOfGeneration();
|
||||
if (reqGenerationTime < oldestGenerationTime) {
|
||||
oldestGenerationTime = reqGenerationTime;
|
||||
}
|
||||
@@ -216,16 +211,19 @@ bool SMS::isThresholdAgeExceeded(const Thread &thread, sc_time const &memClk, si
|
||||
|
||||
// check threshold age according to the thread's MPKC
|
||||
sc_time oldestRequestAge = sc_time_stamp() - oldestGenerationTime;
|
||||
if ((MPKCs[thread] <= MEDIUM_MPKC) && (oldestRequestAge > (MEDIUM_THRESHOLD_AGE * memClk))) {
|
||||
if ((MPKCs[thread] <= MEDIUM_MPKC)
|
||||
&& (oldestRequestAge > (MEDIUM_THRESHOLD_AGE * memClk))) {
|
||||
return true;
|
||||
} else if ((MPKCs[thread] > MEDIUM_MPKC) && (oldestRequestAge > (HIGH_THRESHOLD_AGE * memClk))) {
|
||||
} else if ((MPKCs[thread] > MEDIUM_MPKC)
|
||||
&& (oldestRequestAge > (HIGH_THRESHOLD_AGE * memClk))) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void SMS::updateMPKCs(sc_time const &memClk) {
|
||||
void SMS::updateMPKCs(sc_time const &memClk)
|
||||
{
|
||||
if (sc_time_stamp() % (MPKC_RESET_CYCLE * memClk) <= memClk) {
|
||||
// reset for every 10k clk cycles
|
||||
for (const auto &cacheMiss : cacheMisses) {
|
||||
@@ -235,17 +233,20 @@ void SMS::updateMPKCs(sc_time const &memClk) {
|
||||
} else {
|
||||
// update MPKC for every thread
|
||||
for (const auto &cacheMiss : cacheMisses) {
|
||||
MPKCs[cacheMiss.first] = (cacheMiss.second * 1000.0 * memClk) / (sc_time_stamp());
|
||||
MPKCs[cacheMiss.first] = (cacheMiss.second * 1000.0 * memClk) /
|
||||
(sc_time_stamp());
|
||||
}
|
||||
debugManager.printDebugMessage(name(), "Update MPKCs");
|
||||
}
|
||||
}
|
||||
|
||||
bool SMS::isExceededReqBufferSize(size_t const &exclusiveEndLoc) {
|
||||
bool SMS::isExceededReqBufferSize(size_t const &exclusiveEndLoc)
|
||||
{
|
||||
return exclusiveEndLoc <= Configuration::getInstance().RequestBufferSize;
|
||||
}
|
||||
|
||||
bool SMS::isRequestBuffersEmpty() const {
|
||||
bool SMS::isRequestBuffersEmpty() const
|
||||
{
|
||||
for (const auto &requestBuffer : requestBuffers) {
|
||||
if (!requestBuffer.second.empty()) {
|
||||
return false;
|
||||
@@ -254,7 +255,8 @@ bool SMS::isRequestBuffersEmpty() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SMS::existReadyBatches() const {
|
||||
bool SMS::existReadyBatches() const
|
||||
{
|
||||
for (const auto &each : readyBatchInclusiveEndLocs) {
|
||||
if (!each.second.empty()) {
|
||||
return true;
|
||||
@@ -270,51 +272,45 @@ bool SMS::existReadyBatches() const {
|
||||
* @param begin
|
||||
* @return true if this batch is ready, otherwise false
|
||||
*/
|
||||
bool SMS::batchFormation(sc_time const &memClk, Thread const &thread, std::deque<gp*> const &requestBuffer, size_t const &inclusiveBeginLoc)
|
||||
bool SMS::batchFormation(sc_time const &memClk, Thread const &thread,
|
||||
std::deque<gp *> const &requestBuffer, size_t const &inclusiveBeginLoc)
|
||||
{
|
||||
if (requestBuffer.empty())
|
||||
{
|
||||
if (requestBuffer.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(inclusiveBeginLoc <= requestBuffer.size());
|
||||
if (requestBuffer.size() == inclusiveBeginLoc)
|
||||
{
|
||||
if (requestBuffer.size() == inclusiveBeginLoc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (MPKCs[thread] < LOW_MPKC || isSystemLightlyLoaded())
|
||||
{
|
||||
if (MPKCs[thread] < LOW_MPKC || isSystemLightlyLoaded()) {
|
||||
// bypass requests by forming batch with only one request (threshold age is ZERO)
|
||||
readyBatchInclusiveEndLocs[thread].push_back(inclusiveBeginLoc);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// forming batch with FIFO size & threshold age constraints
|
||||
size_t firstDifferentRowAccessReqLoc = inclusiveBeginLoc;
|
||||
Row firstRow = DramExtension::getRow(requestBuffer[inclusiveBeginLoc]);
|
||||
bool isBatchReady = false;
|
||||
size_t bufferSize = requestBuffer.size();
|
||||
while (firstDifferentRowAccessReqLoc != bufferSize
|
||||
&& DramExtension::getRow(requestBuffer[firstDifferentRowAccessReqLoc]) == firstRow)
|
||||
{
|
||||
&& DramExtension::getRow(requestBuffer[firstDifferentRowAccessReqLoc]) ==
|
||||
firstRow) {
|
||||
++firstDifferentRowAccessReqLoc;
|
||||
if (firstDifferentRowAccessReqLoc < bufferSize)
|
||||
{
|
||||
if (DramExtension::getRow(requestBuffer[firstDifferentRowAccessReqLoc]) != firstRow
|
||||
if (firstDifferentRowAccessReqLoc < bufferSize) {
|
||||
if (DramExtension::getRow(requestBuffer[firstDifferentRowAccessReqLoc]) !=
|
||||
firstRow
|
||||
|| isExceededReqBufferSize(firstDifferentRowAccessReqLoc)
|
||||
|| isThresholdAgeExceeded(thread, memClk, inclusiveBeginLoc, firstDifferentRowAccessReqLoc))
|
||||
{
|
||||
|| isThresholdAgeExceeded(thread, memClk, inclusiveBeginLoc,
|
||||
firstDifferentRowAccessReqLoc)) {
|
||||
isBatchReady = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
if (isExceededReqBufferSize(firstDifferentRowAccessReqLoc)
|
||||
|| isThresholdAgeExceeded(thread, memClk, inclusiveBeginLoc, firstDifferentRowAccessReqLoc))
|
||||
{
|
||||
|| isThresholdAgeExceeded(thread, memClk, inclusiveBeginLoc,
|
||||
firstDifferentRowAccessReqLoc)) {
|
||||
isBatchReady = true;
|
||||
break;
|
||||
}
|
||||
@@ -322,16 +318,13 @@ bool SMS::batchFormation(sc_time const &memClk, Thread const &thread, std::deque
|
||||
}
|
||||
|
||||
// store this ready batch location
|
||||
if (isBatchReady)
|
||||
{
|
||||
if (isBatchReady) {
|
||||
--firstDifferentRowAccessReqLoc;
|
||||
readyBatchInclusiveEndLocs[thread].push_back(firstDifferentRowAccessReqLoc);
|
||||
debugManager.printDebugMessage(name(),
|
||||
"Deem batch ready - thread " + to_string(thread.ID()));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -339,24 +332,20 @@ bool SMS::batchFormation(sc_time const &memClk, Thread const &thread, std::deque
|
||||
|
||||
void SMS::multiBatchFormation(sc_time const &memClk)
|
||||
{
|
||||
for (auto &requestBuffer : requestBuffers)
|
||||
{
|
||||
for (auto &requestBuffer : requestBuffers) {
|
||||
bool formed = false;
|
||||
do
|
||||
{
|
||||
if (readyBatchInclusiveEndLocs[requestBuffer.first].empty())
|
||||
{
|
||||
do {
|
||||
if (readyBatchInclusiveEndLocs[requestBuffer.first].empty()) {
|
||||
formed = batchFormation(memClk, requestBuffer.first, requestBuffer.second, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
formed = batchFormation(memClk, requestBuffer.first, requestBuffer.second, readyBatchInclusiveEndLocs[requestBuffer.first].back() + 1);
|
||||
} else {
|
||||
formed = batchFormation(memClk, requestBuffer.first, requestBuffer.second,
|
||||
readyBatchInclusiveEndLocs[requestBuffer.first].back() + 1);
|
||||
}
|
||||
} while (!requestBuffer.second.empty() && formed);
|
||||
}
|
||||
}
|
||||
|
||||
gp* SMS::getPendingRequest(Bank bank)
|
||||
gp *SMS::getPendingRequest(Bank bank)
|
||||
{
|
||||
for (const auto &requestBuffer : requestBuffers) {
|
||||
for (const auto &request : requestBuffer.second) {
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#define MPKC_RESET_CYCLE 10000
|
||||
|
||||
using namespace std;
|
||||
typedef std::deque<gp*>::iterator gp_deque_iterator;
|
||||
typedef std::deque<gp *>::iterator gp_deque_iterator;
|
||||
|
||||
/**
|
||||
* SMS - Staged Memory Scheduler involves 3 steps:
|
||||
@@ -32,7 +32,9 @@ typedef std::deque<gp*>::iterator gp_deque_iterator;
|
||||
class SMS: public sc_module, public IScheduler
|
||||
{
|
||||
public:
|
||||
SMS(sc_module_name /*_name*/, ControllerCore &controllerCore, unsigned int SJFprobability) : IScheduler(controllerCore), SJFprobability(SJFprobability), debugManager(DebugManager::getInstance())
|
||||
SMS(sc_module_name /*_name*/, ControllerCore &controllerCore,
|
||||
unsigned int SJFprobability) : IScheduler(controllerCore),
|
||||
SJFprobability(SJFprobability), debugManager(DebugManager::getInstance())
|
||||
{
|
||||
// initialize selected thread iterator
|
||||
lastSelectedThread = readyBatchInclusiveEndLocs.end();
|
||||
@@ -45,14 +47,14 @@ public:
|
||||
}
|
||||
|
||||
virtual void schedule(gp *payload) override;
|
||||
virtual std::pair<Command, gp*> getNextRequest(Bank bank) override;
|
||||
virtual gp* getPendingRequest(Bank bank) override;
|
||||
virtual std::pair<Command, gp *> getNextRequest(Bank bank) override;
|
||||
virtual gp *getPendingRequest(Bank bank) override;
|
||||
|
||||
void batchScheduler();
|
||||
|
||||
private:
|
||||
std::map<Thread, std::deque<gp*>> requestBuffers;
|
||||
std::map<Bank, std::deque<gp*>> bankBuffers;
|
||||
std::map<Thread, std::deque<gp *>> requestBuffers;
|
||||
std::map<Bank, std::deque<gp *>> bankBuffers;
|
||||
std::map<Thread, std::deque<size_t>> readyBatchInclusiveEndLocs;
|
||||
|
||||
std::map<Thread, unsigned int> inFlightMemRequestCounter;
|
||||
@@ -63,9 +65,10 @@ private:
|
||||
std::map<Thread, std::deque<size_t>>::iterator lastSelectedThread;
|
||||
sc_event newRequest;
|
||||
|
||||
DebugManager& debugManager;
|
||||
DebugManager &debugManager;
|
||||
|
||||
bool batchFormation(sc_time const &memClk, Thread const &thread, const std::deque<gp*> &requestBuffer, const size_t &inclusiveBeginLoc);
|
||||
bool batchFormation(sc_time const &memClk, Thread const &thread,
|
||||
const std::deque<gp *> &requestBuffer, const size_t &inclusiveBeginLoc);
|
||||
void multiBatchFormation(const sc_time &memClk);
|
||||
bool pickSJF();
|
||||
bool pickRR();
|
||||
@@ -73,7 +76,8 @@ private:
|
||||
|
||||
bool existLowIntensityThread() const;
|
||||
bool isSystemLightlyLoaded() const;
|
||||
bool isThresholdAgeExceeded(const Thread &thread, const sc_time &memClk, const size_t &inclusiveBeginLoc, const size_t &exclusiveEndLoc);
|
||||
bool isThresholdAgeExceeded(const Thread &thread, const sc_time &memClk,
|
||||
const size_t &inclusiveBeginLoc, const size_t &exclusiveEndLoc);
|
||||
bool isExceededReqBufferSize(size_t const &exclusiveEndLoc);
|
||||
void updateMPKCs(const sc_time &memClk);
|
||||
|
||||
|
||||
@@ -50,59 +50,59 @@
|
||||
|
||||
//ThreadLoad::ThreadLoad()
|
||||
//{
|
||||
// // TODO Auto-generated constructor stub
|
||||
// // TODO Auto-generated constructor stub
|
||||
|
||||
//}
|
||||
|
||||
//ThreadLoad::~ThreadLoad()
|
||||
//{
|
||||
// // TODO Auto-generated destructor stub
|
||||
// // 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;
|
||||
// unsigned int maxLoad = 0;
|
||||
// for (auto& bankVectorPair : load)
|
||||
// {
|
||||
// if (bankVectorPair.second.size() > maxLoad)
|
||||
// maxLoad = bankVectorPair.second.size();
|
||||
// }
|
||||
// return maxLoad;
|
||||
//}
|
||||
|
||||
//unsigned int ThreadLoad::getTotalLoad() const
|
||||
//{
|
||||
// unsigned int totalLoad = 0;
|
||||
// for (auto& bankVectorPair : load)
|
||||
// {
|
||||
// totalLoad += bankVectorPair.second.size();
|
||||
// }
|
||||
// return totalLoad;
|
||||
// unsigned int totalLoad = 0;
|
||||
// for (auto& bankVectorPair : load)
|
||||
// {
|
||||
// totalLoad += bankVectorPair.second.size();
|
||||
// }
|
||||
// return totalLoad;
|
||||
//}
|
||||
|
||||
//void ThreadLoad::addTransaction(gp* payload)
|
||||
//{
|
||||
// load[DramExtension::getExtension(payload).getBank()].push_back(payload);
|
||||
// load[DramExtension::getExtension(payload).getBank()].push_back(payload);
|
||||
//}
|
||||
|
||||
//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;
|
||||
// if (lhs.getMaxBankLoad() < rhs.getMaxBankLoad())
|
||||
// return true;
|
||||
// else if (lhs.getMaxBankLoad() == rhs.getMaxBankLoad())
|
||||
// return lhs.getTotalLoad() < rhs.getTotalLoad();
|
||||
// else
|
||||
// return false;
|
||||
//}
|
||||
|
||||
//vector<gp*> ThreadLoad::getTransactions()
|
||||
//{
|
||||
// vector<gp*> result;
|
||||
// for (auto& bankVectorPair : load)
|
||||
// {
|
||||
// result.insert(result.end(), bankVectorPair.second.begin(), bankVectorPair.second.end());
|
||||
// }
|
||||
// return result;
|
||||
// vector<gp*> result;
|
||||
// for (auto& bankVectorPair : load)
|
||||
// {
|
||||
// result.insert(result.end(), bankVectorPair.second.begin(), bankVectorPair.second.end());
|
||||
// }
|
||||
// return result;
|
||||
//}
|
||||
|
||||
//} /* namespace scheduler
|
||||
|
||||
@@ -56,16 +56,16 @@
|
||||
//{
|
||||
//public:
|
||||
// ThreadLoad();d
|
||||
// virtual ~ThreadLoad();
|
||||
// virtual ~ThreadLoad();
|
||||
|
||||
// unsigned int getMaxBankLoad() const;
|
||||
// unsigned int getTotalLoad() const;
|
||||
// unsigned int getMaxBankLoad() const;
|
||||
// unsigned int getTotalLoad() const;
|
||||
|
||||
// void addTransaction(gp* payload);
|
||||
// std::vector<gp*> getTransactions();
|
||||
// void addTransaction(gp* payload);
|
||||
// std::vector<gp*> getTransactions();
|
||||
|
||||
//private:
|
||||
// std::map<Bank,std::vector<gp*>> load;
|
||||
// std::map<Bank,std::vector<gp*>> load;
|
||||
//};
|
||||
|
||||
//bool operator< (const ThreadLoad &lhs, const ThreadLoad &rhs);
|
||||
|
||||
@@ -6,7 +6,7 @@ using std::cout;
|
||||
|
||||
CBit::CBit(VALUE nVal)
|
||||
{
|
||||
m_nValue = nVal;
|
||||
m_nValue = nVal;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,12 +16,9 @@ CBit::~CBit()
|
||||
|
||||
void CBit::Print()
|
||||
{
|
||||
if (m_nValue == ZERO)
|
||||
{
|
||||
cout <<"0";
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "1";
|
||||
}
|
||||
if (m_nValue == ZERO) {
|
||||
cout << "0";
|
||||
} else {
|
||||
cout << "1";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,72 +2,68 @@
|
||||
class CBit
|
||||
{
|
||||
public:
|
||||
enum VALUE
|
||||
{
|
||||
ZERO = 0,
|
||||
ONE = 1
|
||||
};
|
||||
enum VALUE {
|
||||
ZERO = 0,
|
||||
ONE = 1
|
||||
};
|
||||
|
||||
protected:
|
||||
VALUE m_nValue;
|
||||
VALUE m_nValue;
|
||||
|
||||
public:
|
||||
CBit(VALUE nVal = ZERO);
|
||||
virtual ~CBit();
|
||||
CBit(VALUE nVal = ZERO);
|
||||
virtual ~CBit();
|
||||
|
||||
inline void Set() { m_nValue = ONE; };
|
||||
inline void Clear() { m_nValue = ZERO; };
|
||||
inline unsigned Get()
|
||||
{
|
||||
if(m_nValue == ONE)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
};
|
||||
inline void Set()
|
||||
{
|
||||
m_nValue = ONE;
|
||||
};
|
||||
inline void Clear()
|
||||
{
|
||||
m_nValue = ZERO;
|
||||
};
|
||||
inline unsigned Get()
|
||||
{
|
||||
if (m_nValue == ONE)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
};
|
||||
|
||||
void Print();
|
||||
void Print();
|
||||
|
||||
CBit& operator=(unsigned d)
|
||||
{
|
||||
if (d == 0 )
|
||||
{
|
||||
m_nValue = ZERO;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nValue = ONE;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
CBit &operator=(unsigned d)
|
||||
{
|
||||
if (d == 0 ) {
|
||||
m_nValue = ZERO;
|
||||
} else {
|
||||
m_nValue = ONE;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend CBit operator^(CBit l, const CBit& r)
|
||||
{
|
||||
if (l.m_nValue == r.m_nValue)
|
||||
{
|
||||
return CBit(ZERO);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CBit(ONE);
|
||||
}
|
||||
}
|
||||
friend CBit operator^(CBit l, const CBit &r)
|
||||
{
|
||||
if (l.m_nValue == r.m_nValue) {
|
||||
return CBit(ZERO);
|
||||
} else {
|
||||
return CBit(ONE);
|
||||
}
|
||||
}
|
||||
|
||||
CBit& operator^=(const CBit& r)
|
||||
{
|
||||
if (m_nValue == r.m_nValue)
|
||||
{
|
||||
m_nValue = ZERO;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nValue = ONE;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
CBit &operator^=(const CBit &r)
|
||||
{
|
||||
if (m_nValue == r.m_nValue) {
|
||||
m_nValue = ZERO;
|
||||
} else {
|
||||
m_nValue = ONE;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bool operator==(const CBit::VALUE& r)
|
||||
{
|
||||
return m_nValue == r;
|
||||
}
|
||||
inline bool operator==(const CBit::VALUE &r)
|
||||
{
|
||||
return m_nValue == r;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -5,37 +5,35 @@
|
||||
// to store the hamming code and parity bit for a SECDED implementation
|
||||
unsigned ECC::GetNumParityBits(unsigned nDataBits)
|
||||
{
|
||||
unsigned nParityBits = 0;
|
||||
unsigned nParityBits = 0;
|
||||
|
||||
// Function to calculate the nube of bits: n = 2^k - k - 1
|
||||
// ( Source: Hacker's Delight; p. 310; math. function 1 )
|
||||
while (nDataBits > ((1 << nParityBits) - nParityBits - 1))
|
||||
{
|
||||
++nParityBits;
|
||||
}
|
||||
while (nDataBits > ((1 << nParityBits) - nParityBits - 1)) {
|
||||
++nParityBits;
|
||||
}
|
||||
|
||||
return nParityBits+1; // +1 for the parity bit
|
||||
return nParityBits + 1; // +1 for the parity bit
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************************************
|
||||
// Function which extends a given data word to the needed length for a SECDED code
|
||||
void ECC::ExtendWord(CWord & v)
|
||||
void ECC::ExtendWord(CWord &v)
|
||||
{
|
||||
unsigned end = v.GetLength() + ECC::GetNumParityBits(v.GetLength());
|
||||
unsigned end = v.GetLength() + ECC::GetNumParityBits(v.GetLength());
|
||||
|
||||
// Insert x bits for the hamming code at positions where pos = 2^a; a = [0..N]
|
||||
// In "Hacker's Delight" the smallest index is 1 - But in this beautiful C-Code it's 0 as it
|
||||
// should be. That's why there is a '-1' in the call of v.Insert.
|
||||
unsigned i = 1;
|
||||
while (i < end)
|
||||
{
|
||||
v.Insert(i-1, CBit());
|
||||
i <<= 1;
|
||||
}
|
||||
unsigned i = 1;
|
||||
while (i < end) {
|
||||
v.Insert(i - 1, CBit());
|
||||
i <<= 1;
|
||||
}
|
||||
|
||||
// Append one bit for the parity
|
||||
v.Append(CBit());
|
||||
v.Append(CBit());
|
||||
}
|
||||
|
||||
// ************************************************************************************************
|
||||
@@ -43,12 +41,12 @@ void ECC::ExtendWord(CWord & v)
|
||||
// Function ExtendWord must be called before calling this function
|
||||
// The calculated bits are stored in p, so the length of p should be at least
|
||||
// 'GetNumParityBits(#data bits)-1'
|
||||
void ECC::CalculateCheckbits(CWord & v, CWord & p)
|
||||
void ECC::CalculateCheckbits(CWord &v, CWord &p)
|
||||
{
|
||||
unsigned i = 1, l = 0;
|
||||
|
||||
// Last bit is the parity bit - don't use this in the algorithm for hamming code
|
||||
unsigned len = v.GetLength()-1;
|
||||
// Last bit is the parity bit - don't use this in the algorithm for hamming code
|
||||
unsigned len = v.GetLength() - 1;
|
||||
|
||||
// Following Graph should show you the behaviour of this algorithm
|
||||
// #Data bits: 11 #Hamming bits: 4 -> SECDED bits: 16 (incl. parity bit)
|
||||
@@ -61,73 +59,67 @@ void ECC::CalculateCheckbits(CWord & v, CWord & p)
|
||||
// ATTENTION: The order of indices is different from the one in the book,
|
||||
// but it doesn't matter in which order your data or check bits are.
|
||||
// But it should be the same for encoding and decoding
|
||||
while (i < len)
|
||||
{
|
||||
for (unsigned j = (i - 1); j < len; j += (i << 1))
|
||||
{
|
||||
for (unsigned k = 0; k < (i); k++)
|
||||
{
|
||||
if(j + k >= len)
|
||||
break;
|
||||
p[l] ^= v[j + k];
|
||||
}
|
||||
}
|
||||
l++;
|
||||
i <<= 1;
|
||||
}
|
||||
while (i < len) {
|
||||
for (unsigned j = (i - 1); j < len; j += (i << 1)) {
|
||||
for (unsigned k = 0; k < (i); k++) {
|
||||
if (j + k >= len)
|
||||
break;
|
||||
p[l] ^= v[j + k];
|
||||
}
|
||||
}
|
||||
l++;
|
||||
i <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// ************************************************************************************************
|
||||
// Function which inserts the checkbits which were calculated with 'CalculateCheckbits' in the
|
||||
// extended data word. This is needed to calculate a proper parity of ALL bits to achive a SECDED
|
||||
// behaviour.
|
||||
void ECC::InsertCheckbits(CWord& v, CWord p)
|
||||
void ECC::InsertCheckbits(CWord &v, CWord p)
|
||||
{
|
||||
unsigned i = 1, j = 0;
|
||||
while (i <= v.GetLength()-1)
|
||||
{
|
||||
v[i - 1] = p[j++];
|
||||
i <<= 1;
|
||||
}
|
||||
unsigned i = 1, j = 0;
|
||||
while (i <= v.GetLength() - 1) {
|
||||
v[i - 1] = p[j++];
|
||||
i <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************************************
|
||||
// Function which extracts the checkbits out of an extended data word. This is needed to check for
|
||||
// bit error in the data word.
|
||||
void ECC::ExtractCheckbits(CWord v, CWord & p)
|
||||
void ECC::ExtractCheckbits(CWord v, CWord &p)
|
||||
{
|
||||
unsigned i = 1, j = 0;
|
||||
while(i <= v.GetLength()-1)
|
||||
{
|
||||
p[j++] = v[i - 1];
|
||||
i <<= 1;
|
||||
}
|
||||
unsigned i = 1, j = 0;
|
||||
while (i <= v.GetLength() - 1) {
|
||||
p[j++] = v[i - 1];
|
||||
i <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// ************************************************************************************************
|
||||
// Function which calculates the overal parity
|
||||
// Simply XOR all bits
|
||||
void ECC::CalculateParityBit(CWord v, CBit & p)
|
||||
void ECC::CalculateParityBit(CWord v, CBit &p)
|
||||
{
|
||||
// Paritybit
|
||||
p = CBit::ZERO;
|
||||
for (unsigned i = 0; i < v.GetLength(); i++)
|
||||
{
|
||||
p ^= v[i];
|
||||
}
|
||||
// Paritybit
|
||||
p = CBit::ZERO;
|
||||
for (unsigned i = 0; i < v.GetLength(); i++) {
|
||||
p ^= v[i];
|
||||
}
|
||||
}
|
||||
|
||||
// ************************************************************************************************
|
||||
// Function to insert the parity bit into the extended data word
|
||||
void ECC::InsertParityBit(CWord& v, CBit p)
|
||||
void ECC::InsertParityBit(CWord &v, CBit p)
|
||||
{
|
||||
v[v.GetLength() - 1] = p;
|
||||
v[v.GetLength() - 1] = p;
|
||||
}
|
||||
|
||||
// ************************************************************************************************
|
||||
// Function to extract the parity bit out of an extended data word.
|
||||
void ECC::ExtractParityBit(CWord v, CBit & p)
|
||||
void ECC::ExtractParityBit(CWord v, CBit &p)
|
||||
{
|
||||
p = v[v.GetLength() - 1];
|
||||
p = v[v.GetLength() - 1];
|
||||
}
|
||||
|
||||
@@ -21,19 +21,18 @@
|
||||
// For further details read chapter 15 of "Hacker's Delight - second Edition"
|
||||
// ************************************************************************************************
|
||||
|
||||
namespace ECC
|
||||
{
|
||||
unsigned GetNumParityBits(unsigned nDataBits);
|
||||
namespace ECC {
|
||||
unsigned GetNumParityBits(unsigned nDataBits);
|
||||
|
||||
// Extends the data word that it can be used with hamming code
|
||||
// Several bits will be included at specific places
|
||||
void ExtendWord(CWord &v);
|
||||
// Extends the data word that it can be used with hamming code
|
||||
// Several bits will be included at specific places
|
||||
void ExtendWord(CWord &v);
|
||||
|
||||
void CalculateCheckbits(CWord &v, CWord & p);
|
||||
void InsertCheckbits(CWord& v, CWord p);
|
||||
void ExtractCheckbits(CWord v, CWord& p);
|
||||
void CalculateCheckbits(CWord &v, CWord &p);
|
||||
void InsertCheckbits(CWord &v, CWord p);
|
||||
void ExtractCheckbits(CWord v, CWord &p);
|
||||
|
||||
void CalculateParityBit(CWord v, CBit& p);
|
||||
void InsertParityBit(CWord& v, CBit p);
|
||||
void ExtractParityBit(CWord v, CBit& p);
|
||||
void CalculateParityBit(CWord v, CBit &p);
|
||||
void InsertParityBit(CWord &v, CBit p);
|
||||
void ExtractParityBit(CWord v, CBit &p);
|
||||
}
|
||||
|
||||
@@ -7,121 +7,109 @@
|
||||
|
||||
int main()
|
||||
{
|
||||
// Random number init
|
||||
srand(time(NULL));
|
||||
// Random number init
|
||||
srand(time(NULL));
|
||||
|
||||
// Erstellen
|
||||
unsigned size = 4;
|
||||
CWord p(ECC::GetNumParityBits(size)), v(size);
|
||||
// Erstellen
|
||||
unsigned size = 4;
|
||||
CWord p(ECC::GetNumParityBits(size)), v(size);
|
||||
|
||||
// Daten eingeben
|
||||
for (unsigned a = 0; a < 16; a++)
|
||||
{
|
||||
v = a;
|
||||
v.Rotate();
|
||||
// Daten eingeben
|
||||
for (unsigned a = 0; a < 16; a++) {
|
||||
v = a;
|
||||
v.Rotate();
|
||||
|
||||
ECC::ExtendWord(v);
|
||||
printf("%d:\t", a);
|
||||
ECC::ExtendWord(v);
|
||||
printf("%d:\t", a);
|
||||
|
||||
p = 0;
|
||||
ECC::CalculateCheckbits(v, p);
|
||||
ECC::InsertCheckbits(v, p);
|
||||
ECC::CalculateParityBit(v, p[3]);
|
||||
ECC::InsertParityBit(v, p[3]);
|
||||
p = 0;
|
||||
ECC::CalculateCheckbits(v, p);
|
||||
ECC::InsertCheckbits(v, p);
|
||||
ECC::CalculateParityBit(v, p[3]);
|
||||
ECC::InsertParityBit(v, p[3]);
|
||||
|
||||
v.Print();
|
||||
v.Print();
|
||||
|
||||
v.Resize(size);
|
||||
}
|
||||
v.Resize(size);
|
||||
}
|
||||
|
||||
printf("\r\n");
|
||||
printf("\r\n");
|
||||
|
||||
for (unsigned x = 0; x < 100; x++)
|
||||
{
|
||||
//Get random number
|
||||
unsigned a = rand() % 16;
|
||||
for (unsigned x = 0; x < 100; x++) {
|
||||
//Get random number
|
||||
unsigned a = rand() % 16;
|
||||
|
||||
v.Resize(size);
|
||||
v = a;
|
||||
v.Rotate();
|
||||
v.Resize(size);
|
||||
v = a;
|
||||
v.Rotate();
|
||||
|
||||
ECC::ExtendWord(v);
|
||||
ECC::ExtendWord(v);
|
||||
|
||||
p = 0;
|
||||
ECC::CalculateCheckbits(v, p);
|
||||
ECC::InsertCheckbits(v, p);
|
||||
ECC::CalculateParityBit(v, p[3]);
|
||||
ECC::InsertParityBit(v, p[3]);
|
||||
v.Print();
|
||||
p = 0;
|
||||
ECC::CalculateCheckbits(v, p);
|
||||
ECC::InsertCheckbits(v, p);
|
||||
ECC::CalculateParityBit(v, p[3]);
|
||||
ECC::InsertParityBit(v, p[3]);
|
||||
v.Print();
|
||||
|
||||
// Insert error
|
||||
unsigned pos = rand() % 8;
|
||||
v[pos] ^= CBit(CBit::ONE);
|
||||
// Insert error
|
||||
unsigned pos = rand() % 8;
|
||||
v[pos] ^= CBit(CBit::ONE);
|
||||
|
||||
printf("Data: %d, Error at pos %d: ", a, pos + 1);
|
||||
v[pos].Print();
|
||||
printf("\r\n");
|
||||
v.Print();
|
||||
printf("Data: %d, Error at pos %d: ", a, pos + 1);
|
||||
v[pos].Print();
|
||||
printf("\r\n");
|
||||
v.Print();
|
||||
|
||||
p = 0;
|
||||
ECC::CalculateCheckbits(v, p);
|
||||
ECC::CalculateParityBit(v, p[3]);
|
||||
p = 0;
|
||||
ECC::CalculateCheckbits(v, p);
|
||||
ECC::CalculateParityBit(v, p[3]);
|
||||
|
||||
printf("%d:\t", a);
|
||||
printf("%d:\t", a);
|
||||
|
||||
p.Print();
|
||||
p.Print();
|
||||
|
||||
// Interpreting Data
|
||||
// Interpreting Data
|
||||
|
||||
unsigned syndrome = 0;
|
||||
for (unsigned i = 0; i < p.GetLength() - 1; i++)
|
||||
{
|
||||
if (p[i] == CBit::ONE)
|
||||
syndrome += (1 << i);
|
||||
}
|
||||
unsigned syndrome = 0;
|
||||
for (unsigned i = 0; i < p.GetLength() - 1; i++) {
|
||||
if (p[i] == CBit::ONE)
|
||||
syndrome += (1 << i);
|
||||
}
|
||||
|
||||
if (p[3] == CBit::ZERO)
|
||||
{
|
||||
// Parity even
|
||||
if (p[3] == CBit::ZERO) {
|
||||
// Parity even
|
||||
|
||||
if (syndrome)
|
||||
{
|
||||
// Double error
|
||||
printf("Double error detected.\r\n");
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No Error
|
||||
printf("No error detected.\r\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Parity odd
|
||||
if (syndrome) {
|
||||
// Double error
|
||||
printf("Double error detected.\r\n");
|
||||
break;
|
||||
} else {
|
||||
// No Error
|
||||
printf("No error detected.\r\n");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Parity odd
|
||||
|
||||
if (syndrome)
|
||||
{
|
||||
// Bit error
|
||||
printf("Error detected in Bit %d.\r\n", syndrome);
|
||||
if (syndrome == pos + 1)
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Overall parity Error
|
||||
printf("Overall parity error detected.\r\n");
|
||||
if (pos == 7 || pos == 3 || pos == 1 || pos == 0)
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
system("pause");
|
||||
if (syndrome) {
|
||||
// Bit error
|
||||
printf("Error detected in Bit %d.\r\n", syndrome);
|
||||
if (syndrome == pos + 1)
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
} else {
|
||||
// Overall parity Error
|
||||
printf("Overall parity error detected.\r\n");
|
||||
if (pos == 7 || pos == 3 || pos == 1 || pos == 0)
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
system("pause");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
using std::cout;
|
||||
|
||||
CWord::CWord(unsigned nBitLength)
|
||||
: m_nBitLength(nBitLength)
|
||||
: m_nBitLength(nBitLength)
|
||||
{
|
||||
m_word.resize(nBitLength);
|
||||
m_word.resize(nBitLength);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,141 +17,127 @@ CWord::~CWord()
|
||||
{
|
||||
}
|
||||
|
||||
CBit * CWord::GetAt(unsigned nBitPos)
|
||||
CBit *CWord::GetAt(unsigned nBitPos)
|
||||
{
|
||||
if (nBitPos < m_nBitLength)
|
||||
{
|
||||
return &m_word.at(nBitPos);
|
||||
}
|
||||
if (nBitPos < m_nBitLength) {
|
||||
return &m_word.at(nBitPos);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CWord::Set(unsigned data)
|
||||
{
|
||||
deque<CBit>::iterator it;
|
||||
if (m_nBitLength < sizeof(data))
|
||||
{
|
||||
it = m_word.begin();
|
||||
for (unsigned i = 0; i < m_nBitLength; i++)
|
||||
{
|
||||
(*it++) = data & 1;
|
||||
data >>= 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (it = m_word.begin(); it != m_word.end(); it++)
|
||||
{
|
||||
(*it) = data & 1;
|
||||
data >>= 1;
|
||||
}
|
||||
}
|
||||
deque<CBit>::iterator it;
|
||||
if (m_nBitLength < sizeof(data)) {
|
||||
it = m_word.begin();
|
||||
for (unsigned i = 0; i < m_nBitLength; i++) {
|
||||
(*it++) = data & 1;
|
||||
data >>= 1;
|
||||
}
|
||||
} else {
|
||||
for (it = m_word.begin(); it != m_word.end(); it++) {
|
||||
(*it) = data & 1;
|
||||
data >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CWord::Set(const unsigned char* data, unsigned lengthInBits)
|
||||
void CWord::Set(const unsigned char *data, unsigned lengthInBits)
|
||||
{
|
||||
deque<CBit>::iterator it;
|
||||
if (m_nBitLength < lengthInBits)
|
||||
{
|
||||
it = m_word.begin();
|
||||
for (unsigned pos = 0; pos < m_nBitLength; pos++)
|
||||
{
|
||||
(*it) = data[pos>>3] & (1 << (7-(pos&7)));
|
||||
it++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned pos = 0;
|
||||
for (it = m_word.begin(); it != m_word.end(); it++)
|
||||
{
|
||||
(*it) = data[pos>>3] & (1 << (7-(pos&7)));
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
deque<CBit>::iterator it;
|
||||
if (m_nBitLength < lengthInBits) {
|
||||
it = m_word.begin();
|
||||
for (unsigned pos = 0; pos < m_nBitLength; pos++) {
|
||||
(*it) = data[pos >> 3] & (1 << (7 - (pos & 7)));
|
||||
it++;
|
||||
}
|
||||
} else {
|
||||
unsigned pos = 0;
|
||||
for (it = m_word.begin(); it != m_word.end(); it++) {
|
||||
(*it) = data[pos >> 3] & (1 << (7 - (pos & 7)));
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CWord::Rotate()
|
||||
{
|
||||
deque<CBit> buffer = m_word;
|
||||
for (unsigned i = 0; i < m_nBitLength; i++)
|
||||
{
|
||||
m_word.at(m_nBitLength -i -1) = buffer.at(i);
|
||||
}
|
||||
deque<CBit> buffer = m_word;
|
||||
for (unsigned i = 0; i < m_nBitLength; i++) {
|
||||
m_word.at(m_nBitLength - i - 1) = buffer.at(i);
|
||||
}
|
||||
}
|
||||
|
||||
bool CWord::Insert(unsigned npos, CBit b)
|
||||
{
|
||||
if (npos >= m_nBitLength)
|
||||
return false;
|
||||
if (npos >= m_nBitLength)
|
||||
return false;
|
||||
|
||||
deque<CBit>::iterator it = m_word.begin() + npos;
|
||||
m_word.insert(it, b);
|
||||
deque<CBit>::iterator it = m_word.begin() + npos;
|
||||
m_word.insert(it, b);
|
||||
|
||||
m_nBitLength++;
|
||||
m_nBitLength++;
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CWord::Delete(unsigned npos)
|
||||
{
|
||||
if (npos >= m_nBitLength)
|
||||
return false;
|
||||
if (npos >= m_nBitLength)
|
||||
return false;
|
||||
|
||||
deque<CBit>::iterator it = m_word.begin() + npos;
|
||||
m_word.erase(it);
|
||||
deque<CBit>::iterator it = m_word.begin() + npos;
|
||||
m_word.erase(it);
|
||||
|
||||
m_nBitLength++;
|
||||
m_nBitLength++;
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CWord::Append(CBit b)
|
||||
{
|
||||
m_word.push_back(b);
|
||||
m_word.push_back(b);
|
||||
|
||||
m_nBitLength++;
|
||||
m_nBitLength++;
|
||||
}
|
||||
|
||||
void CWord::Resize(unsigned nsize)
|
||||
{
|
||||
m_word.resize(nsize);
|
||||
m_nBitLength = nsize;
|
||||
m_word.resize(nsize);
|
||||
m_nBitLength = nsize;
|
||||
}
|
||||
|
||||
bool CWord::PartShiftRight(unsigned nPos, unsigned /*nShift*/)
|
||||
{
|
||||
if(nPos >= m_nBitLength)
|
||||
return false;
|
||||
if (nPos >= m_nBitLength)
|
||||
return false;
|
||||
|
||||
/*for (unsigned i = 0; i < nShift; i++)
|
||||
{
|
||||
m_word.insert()
|
||||
}*/
|
||||
/*for (unsigned i = 0; i < nShift; i++)
|
||||
{
|
||||
m_word.insert()
|
||||
}*/
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CWord::Print()
|
||||
{
|
||||
deque<CBit>::iterator it;
|
||||
for (it = m_word.begin(); it != m_word.end(); it++)
|
||||
{
|
||||
(*it).Print();
|
||||
}
|
||||
cout << "\r\n";
|
||||
deque<CBit>::iterator it;
|
||||
for (it = m_word.begin(); it != m_word.end(); it++) {
|
||||
(*it).Print();
|
||||
}
|
||||
cout << "\r\n";
|
||||
}
|
||||
|
||||
void CWord::Copy(unsigned char* ptr)
|
||||
void CWord::Copy(unsigned char *ptr)
|
||||
{
|
||||
unsigned len = ceil(m_word.size()/8);
|
||||
unsigned len = ceil(m_word.size() / 8);
|
||||
memset(ptr, 0, len);
|
||||
|
||||
unsigned pos = 0;
|
||||
for(auto it = m_word.begin(); it != m_word.end(); it++)
|
||||
{
|
||||
ptr[pos>>3] |= (*it).Get() << (7-(pos&7));
|
||||
++pos;
|
||||
}
|
||||
unsigned pos = 0;
|
||||
for (auto it = m_word.begin(); it != m_word.end(); it++) {
|
||||
ptr[pos >> 3] |= (*it).Get() << (7 - (pos & 7));
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,54 +10,56 @@ class CWord
|
||||
{
|
||||
protected:
|
||||
|
||||
unsigned m_nBitLength;
|
||||
deque<CBit> m_word;
|
||||
unsigned m_nBitLength;
|
||||
deque<CBit> m_word;
|
||||
|
||||
|
||||
public:
|
||||
CWord(unsigned nBitLength);
|
||||
virtual ~CWord();
|
||||
CWord(unsigned nBitLength);
|
||||
virtual ~CWord();
|
||||
|
||||
CBit* GetAt(unsigned nBitPos);
|
||||
CBit *GetAt(unsigned nBitPos);
|
||||
|
||||
void Set(unsigned data);
|
||||
void Set(const unsigned char* data, unsigned lengthInBits);
|
||||
void Rotate();
|
||||
void Set(unsigned data);
|
||||
void Set(const unsigned char *data, unsigned lengthInBits);
|
||||
void Rotate();
|
||||
|
||||
bool Insert(unsigned npos, CBit b);
|
||||
bool Delete(unsigned npos);
|
||||
bool Insert(unsigned npos, CBit b);
|
||||
bool Delete(unsigned npos);
|
||||
|
||||
void Copy(unsigned char* ptr);
|
||||
void Copy(unsigned char *ptr);
|
||||
|
||||
void Append(CBit b);
|
||||
void Append(CBit b);
|
||||
|
||||
void Resize(unsigned nsize);
|
||||
void Resize(unsigned nsize);
|
||||
|
||||
bool PartShiftRight(unsigned nPos, unsigned nShift);
|
||||
bool PartShiftRight(unsigned nPos, unsigned nShift);
|
||||
|
||||
inline unsigned GetLength() const { return m_nBitLength; };
|
||||
inline unsigned GetLength() const
|
||||
{
|
||||
return m_nBitLength;
|
||||
};
|
||||
|
||||
void Print();
|
||||
void Print();
|
||||
|
||||
CWord& operator=(unsigned d)
|
||||
{
|
||||
Set(d);
|
||||
return *this;
|
||||
}
|
||||
CWord &operator=(unsigned d)
|
||||
{
|
||||
Set(d);
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBit& operator[](unsigned nPos)
|
||||
{
|
||||
return m_word.at(nPos);
|
||||
}
|
||||
CBit &operator[](unsigned nPos)
|
||||
{
|
||||
return m_word.at(nPos);
|
||||
}
|
||||
|
||||
friend CWord operator >> (CWord l, const unsigned& r)
|
||||
{
|
||||
for (unsigned i = 0; i < r; i++)
|
||||
{
|
||||
l.m_word.pop_front();
|
||||
l.m_word.push_back(CBit(CBit::VALUE::ZERO));
|
||||
}
|
||||
return l;
|
||||
}
|
||||
friend CWord operator >> (CWord l, const unsigned &r)
|
||||
{
|
||||
for (unsigned i = 0; i < r; i++) {
|
||||
l.m_word.pop_front();
|
||||
l.m_word.push_back(CBit(CBit::VALUE::ZERO));
|
||||
}
|
||||
return l;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,31 +1,30 @@
|
||||
#include "eccbaseclass.h"
|
||||
|
||||
tlm::tlm_sync_enum ECCBaseClass::nb_transport_fw( int id, tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_time& delay )
|
||||
tlm::tlm_sync_enum ECCBaseClass::nb_transport_fw( int id,
|
||||
tlm::tlm_generic_payload &trans, tlm::tlm_phase &phase, sc_time &delay )
|
||||
{
|
||||
if(trans.get_command() == TLM_WRITE_COMMAND && phase == BEGIN_REQ)
|
||||
{
|
||||
if (trans.get_command() == TLM_WRITE_COMMAND && phase == BEGIN_REQ) {
|
||||
// Allocate memory for encoded data using the size provided by AllocationEncode
|
||||
unsigned nEncodedDataSize = AllocationSize(trans.get_data_length());
|
||||
assert(nEncodedDataSize != 0);
|
||||
unsigned char* pEncodedData = new unsigned char[nEncodedDataSize];
|
||||
unsigned char *pEncodedData = new unsigned char[nEncodedDataSize];
|
||||
|
||||
// Save memory pointer and size
|
||||
m_mDataPointer[pEncodedData].pData = trans.get_data_ptr();
|
||||
m_mDataPointer[pEncodedData].nDataSize = trans.get_data_length();
|
||||
|
||||
// Data Encoding
|
||||
Encode(trans.get_data_ptr(), trans.get_data_length(), pEncodedData, nEncodedDataSize);
|
||||
Encode(trans.get_data_ptr(), trans.get_data_length(), pEncodedData,
|
||||
nEncodedDataSize);
|
||||
|
||||
// Change transport data length and pointer
|
||||
trans.set_data_length(nEncodedDataSize);
|
||||
trans.set_data_ptr(pEncodedData);
|
||||
}
|
||||
else if(trans.get_command() == TLM_READ_COMMAND && phase == BEGIN_REQ)
|
||||
{
|
||||
} else if (trans.get_command() == TLM_READ_COMMAND && phase == BEGIN_REQ) {
|
||||
// Allocate memory for reading data using the size provided by AllocationEncode
|
||||
unsigned nReadDataSize = AllocationSize(trans.get_data_length());
|
||||
assert(nReadDataSize != 0);
|
||||
unsigned char* pReadData = new unsigned char[nReadDataSize];
|
||||
unsigned char *pReadData = new unsigned char[nReadDataSize];
|
||||
|
||||
// Save memory pointer and size
|
||||
m_mDataPointer[pReadData].pData = trans.get_data_ptr();
|
||||
@@ -41,16 +40,17 @@ tlm::tlm_sync_enum ECCBaseClass::nb_transport_fw( int id, tlm::tlm_generic_paylo
|
||||
|
||||
|
||||
// Backward interface
|
||||
tlm::tlm_sync_enum ECCBaseClass::nb_transport_bw( int id, tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_time& delay )
|
||||
tlm::tlm_sync_enum ECCBaseClass::nb_transport_bw( int id,
|
||||
tlm::tlm_generic_payload &trans, tlm::tlm_phase &phase, sc_time &delay )
|
||||
{
|
||||
if(trans.get_command() == TLM_READ_COMMAND && phase == BEGIN_RESP)
|
||||
{
|
||||
if (trans.get_command() == TLM_READ_COMMAND && phase == BEGIN_RESP) {
|
||||
//Look for the corresponding data pointer for decoding
|
||||
auto it = m_mDataPointer.find(trans.get_data_ptr());
|
||||
assert(it != m_mDataPointer.end());
|
||||
|
||||
// Data Decoding
|
||||
Decode(trans.get_data_ptr(), trans.get_data_length(), it->second.pData, it->second.nDataSize);
|
||||
Decode(trans.get_data_ptr(), trans.get_data_length(), it->second.pData,
|
||||
it->second.nDataSize);
|
||||
|
||||
// delete data pointer from map
|
||||
m_mDataPointer.erase(it);
|
||||
@@ -61,9 +61,7 @@ tlm::tlm_sync_enum ECCBaseClass::nb_transport_bw( int id, tlm::tlm_generic_paylo
|
||||
// Set data pointer and size for decoded data
|
||||
trans.set_data_ptr(it->second.pData);
|
||||
trans.set_data_length(it->second.nDataSize);
|
||||
}
|
||||
else if(trans.get_command() == TLM_WRITE_COMMAND && phase == BEGIN_RESP)
|
||||
{
|
||||
} else if (trans.get_command() == TLM_WRITE_COMMAND && phase == BEGIN_RESP) {
|
||||
//Look for the corresponding data pointer for decoding
|
||||
auto it = m_mDataPointer.find(trans.get_data_ptr());
|
||||
assert(it != m_mDataPointer.end());
|
||||
|
||||
@@ -17,14 +17,13 @@ using namespace tlm;
|
||||
class ECCBaseClass : sc_module
|
||||
{
|
||||
public:
|
||||
struct DataStruct
|
||||
{
|
||||
unsigned char* pData;
|
||||
struct DataStruct {
|
||||
unsigned char *pData;
|
||||
unsigned int nDataSize;
|
||||
};
|
||||
|
||||
private:
|
||||
map<unsigned char*, DataStruct> m_mDataPointer;
|
||||
map<unsigned char *, DataStruct> m_mDataPointer;
|
||||
|
||||
public:
|
||||
// Function prototype for calculated the size of memory needed for saving the encoded data
|
||||
@@ -37,14 +36,16 @@ protected:
|
||||
// Data pointer is provided in pDataIn, length in Bytes provided in nDataIn
|
||||
// Result should be written in pDataOut, which has a size of nDataOut.
|
||||
// pDataOut is already allocated with a size given by function AllocationEncode
|
||||
virtual void Encode(const unsigned char* pDataIn, const unsigned nDataIn, unsigned char* pDataOut, const unsigned nDataOut) = 0;
|
||||
virtual void Encode(const unsigned char *pDataIn, const unsigned nDataIn,
|
||||
unsigned char *pDataOut, const unsigned nDataOut) = 0;
|
||||
|
||||
|
||||
// Function prototype for decoding data.
|
||||
// Data pointer is provided in pDataIn, length in Bytes provided in nDataIn
|
||||
// Result should be written in pDataOut, which has a size of nDataOut.
|
||||
// pDataOut is already allocated with a size given by function AllocationDecode
|
||||
virtual void Decode(const unsigned char* pDataIn, const unsigned nDataIn, unsigned char* pDataOut, const unsigned nDataOut) = 0;
|
||||
virtual void Decode(const unsigned char *pDataIn, const unsigned nDataIn,
|
||||
unsigned char *pDataOut, const unsigned nDataOut) = 0;
|
||||
|
||||
public:
|
||||
tlm_utils::multi_passthrough_target_socket<ECCBaseClass> t_socket;
|
||||
@@ -58,10 +59,12 @@ public:
|
||||
i_socket.register_nb_transport_bw(this, &ECCBaseClass::nb_transport_bw);
|
||||
}
|
||||
// Forward interface
|
||||
tlm::tlm_sync_enum nb_transport_fw( int id, tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_time& delay );
|
||||
tlm::tlm_sync_enum nb_transport_fw( int id, tlm::tlm_generic_payload &trans,
|
||||
tlm::tlm_phase &phase, sc_time &delay );
|
||||
|
||||
// Backward interface
|
||||
tlm::tlm_sync_enum nb_transport_bw( int id, tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_time& delay );
|
||||
tlm::tlm_sync_enum nb_transport_bw( int id, tlm::tlm_generic_payload &trans,
|
||||
tlm::tlm_phase &phase, sc_time &delay );
|
||||
};
|
||||
|
||||
#endif // ECCBASECLASS_H
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user