Skip to content

Commit

Permalink
Tests for LSU
Browse files Browse the repository at this point in the history
  • Loading branch information
h0lyalg0rithm committed Oct 12, 2023
1 parent 7120d89 commit 7f2402b
Show file tree
Hide file tree
Showing 12 changed files with 438 additions and 46 deletions.
71 changes: 41 additions & 30 deletions core/LSU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ namespace olympia
sparta::Unit(node),
ldst_inst_queue_("lsu_inst_queue", p->ldst_inst_queue_size, getClock()),
ldst_inst_queue_size_(p->ldst_inst_queue_size),
load_queue_("load_queue", p->ld_queue_size, getClock()),
load_queue_size_(p->ld_queue_size),
store_queue_("store_queue", p->st_queue_size, getClock()),
store_queue_size_(p->st_queue_size),
replay_buffer_("replay_buffer", p->replay_buffer_size, getClock()),
replay_buffer_size_(p->replay_buffer_size),
replay_issue_delay_(p->replay_issue_delay),
Expand All @@ -30,7 +26,6 @@ namespace olympia
memory_access_allocator),
ldst_pipeline_("LoadStorePipeline",
static_cast<uint32_t>(p->mmu_lookup_stage_length + p->cache_lookup_stage_length + p->cache_read_stage_length + 2), getClock()),
stall_pipeline_on_miss_(p->stall_pipeline_on_miss),
allow_speculative_load_exec_(p->allow_speculative_load_exec)
{
setupPipelineLength(p);
Expand All @@ -39,8 +34,6 @@ namespace olympia
ldst_pipeline_.enableCollection(node);
ldst_inst_queue_.enableCollection(node);

load_queue_.enableCollection(node);
store_queue_.enableCollection(node);
replay_buffer_.enableCollection(node);

// Startup handler for sending initial credits
Expand Down Expand Up @@ -105,7 +98,6 @@ namespace olympia
(static_cast<uint32_t>(COMPLETE),
CREATE_SPARTA_HANDLER(LSU, completeInst_));

uev_pipe_stall_ >> uev_issue_inst_;
// NOTE:
// To resolve the race condition when:
// Both cache and MMU try to drive the single BIU port at the same cycle
Expand All @@ -117,8 +109,13 @@ namespace olympia

LSU::~LSU()
{
DLOG(getContainer()->getLocation() << ": " << load_store_info_allocator_.getNumAllocated() << " LoadStoreInstInfo objects allocated/created");
DLOG(getContainer()->getLocation() << ": " << memory_access_allocator_.getNumAllocated() << " MemoryAccessInfo objects allocated/created");
DLOG(
getContainer()->getLocation()
<< ": " << load_store_info_allocator_.getNumAllocated() << " LoadStoreInstInfo objects allocated/created"
);
DLOG(
getContainer()->getLocation()
<< ": " << memory_access_allocator_.getNumAllocated() << " MemoryAccessInfo objects allocated/created");
}
void LSU::setupPipelineLength(const LSU::LSUParameterSet* p)
{
Expand Down Expand Up @@ -355,7 +352,7 @@ namespace olympia
<< " " << updated_memory_access_info_ptr);
mmu_hit_ = updated_memory_access_info_ptr->getPhyAddrStatus();

if(mmu_hit_ && allow_speculative_load_exec_){
if(updated_memory_access_info_ptr->getInstPtr()->isStoreInst() && mmu_hit_ && allow_speculative_load_exec_){
ILOG("Aborting speculative loads " << updated_memory_access_info_ptr);
abortYoungerLoads(updated_memory_access_info_ptr);
}
Expand Down Expand Up @@ -685,10 +682,6 @@ namespace olympia
// instruction issue arbitration should always succeed, even when flush happens.
// Otherwise, assertion error is fired inside arbitrateInstIssue_()
}

void LSU::pipeStall_()
{}

void LSU::replayReady_(const InstPtr & replay_inst_ptr)
{
ILOG("Replay inst ready " << replay_inst_ptr);
Expand All @@ -702,7 +695,10 @@ namespace olympia
{
load_store_info_ptr->setState(LoadStoreInstInfo::IssueState::READY);
}
load_store_info_ptr->setPriority(LoadStoreInstInfo::IssuePriority::HIGHEST);
auto issue_priority = load_store_info_ptr->getMemoryAccessInfoPtr()->getPhyAddrStatus()
? LoadStoreInstInfo::IssuePriority::CACHE_PENDING
: LoadStoreInstInfo::IssuePriority::MMU_PENDING;
load_store_info_ptr->setPriority(issue_priority);
}
}
if (isReadyToIssueInsts_())
Expand Down Expand Up @@ -782,6 +778,7 @@ namespace olympia
return true;
}

// Only called if allow_spec_load_exec is true
void LSU::readyDependentLoads(const LoadStoreInstInfoPtr &store_inst_ptr){
bool found = false;
for(auto &ldst_inst_ptr: ldst_inst_queue_){
Expand All @@ -792,7 +789,6 @@ namespace olympia

// Only ready loads which have register operands ready
if(inst_ptr->getStatus() == Inst::Status::DISPATCHED &&
// inst_ptr->getTargetVAddr() == store_inst_ptr->getInstPtr()->getTargetVAddr() &&
scoreboard_views_[core_types::RF_INTEGER]->isSet(inst_ptr->getSrcRegisterBitMask(core_types::RF_INTEGER))){
ILOG("Updating inst to schedule " << inst_ptr << " " << ldst_inst_ptr);
updateIssuePriorityAfterNewDispatch_(inst_ptr);
Expand Down Expand Up @@ -836,32 +832,35 @@ namespace olympia
}
}
}

ILOG("Age of the oldest instruction " << min_inst_age << " for " << inst_ptr);
if(min_inst_age == UINT64_MAX){
ILOG("No younger instruction to deallocate");
return;
}
ILOG("Age of the oldest instruction " << min_inst_age << " for " << inst_ptr << inst_ptr->getTargetVAddr());
// Remove instructions younger than the oldest load that was removed
for (auto iter = queue.begin(); iter != queue.end(); iter++) {
if(!iter.isValid()){
break;
}
auto iter = queue.begin();
while(iter != queue.end()){
if((*iter)->getInstPtr() == inst_ptr){
++iter;
continue;
}

if ((*iter)->getInstUniqueID() > min_inst_age){
if ((*iter)->getInstUniqueID() >= min_inst_age){
(*iter)->setState(LoadStoreInstInfo::IssueState::READY);
ILOG("Aborted younger load " << *iter);
ILOG("Aborted younger load " << *iter << (*iter)->getInstPtr()->getTargetVAddr());
invalidatePipeline((*iter)->getInstPtr());
queue.erase(iter);
queue.erase(iter++);
}else{
++iter;
}
}
ILOG("Done");
}

void LSU::invalidatePipeline(const InstPtr & inst_ptr){
auto ac_stage_id = static_cast<uint32_t>(ADDRESS_CALCULATION);
auto mmu_stage_id = static_cast<uint32_t>(MMU_LOOKUP);
auto cache_lookup_stage_id = static_cast<uint32_t>(CACHE_LOOKUP);
auto cache_read_stage_id = static_cast<uint32_t>(CACHE_READ);
auto complete_stage_id = static_cast<uint32_t>(COMPLETE);

if(ldst_pipeline_.isValid(ac_stage_id)){
auto &pipeline_inst = ldst_pipeline_[ac_stage_id]->getInstPtr();
Expand All @@ -887,6 +886,12 @@ namespace olympia
ldst_pipeline_.invalidateStage(cache_read_stage_id);
}
}
if(ldst_pipeline_.isValid(complete_stage_id)){
auto &pipeline_inst = ldst_pipeline_[complete_stage_id]->getInstPtr();
if(pipeline_inst == inst_ptr){
ldst_pipeline_.invalidateStage(complete_stage_id);
}
}
}
// Append new load/store instruction into issue queue
void LSU::appendIssueQueue_(const LoadStoreInstInfoPtr & inst_info_ptr)
Expand Down Expand Up @@ -1058,7 +1063,10 @@ namespace olympia

if (inst_info_ptr->getInstPtr() == inst_ptr) {
// Update issue priority for this outstanding TLB miss
inst_info_ptr->setState(LoadStoreInstInfo::IssueState::READY);
if(inst_info_ptr->getState() != LoadStoreInstInfo::IssueState::ISSUED)
{
inst_info_ptr->setState(LoadStoreInstInfo::IssueState::READY);
}
inst_info_ptr->setPriority(LoadStoreInstInfo::IssuePriority::MMU_RELOAD);

// NOTE:
Expand Down Expand Up @@ -1098,7 +1106,10 @@ namespace olympia

if (inst_info_ptr->getInstPtr() == inst_ptr) {
// Update issue priority for this outstanding cache miss
inst_info_ptr->setState(LoadStoreInstInfo::IssueState::READY);
if(inst_info_ptr->getState() != LoadStoreInstInfo::IssueState::ISSUED)
{
inst_info_ptr->setState(LoadStoreInstInfo::IssueState::READY);
}
inst_info_ptr->setPriority(LoadStoreInstInfo::IssuePriority::CACHE_RELOAD);

// NOTE:
Expand Down
17 changes: 1 addition & 16 deletions core/LSU.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,9 @@ namespace olympia

// Parameters for ldst_inst_queue
PARAMETER(uint32_t, ldst_inst_queue_size, 8, "LSU ldst inst queue size")
PARAMETER(uint32_t, st_queue_size, ldst_inst_queue_size, "Store Queue size")
PARAMETER(uint32_t, ld_queue_size, ldst_inst_queue_size, "Load Queue size")
PARAMETER(uint32_t, replay_buffer_size, ldst_inst_queue_size, "Replay buffer size")
PARAMETER(uint32_t, replay_issue_delay, 3, "Replay Issue delay")
// LSU microarchitecture parameters
PARAMETER(bool, stall_pipeline_on_miss, false, "Stall pipeline on miss event")
PARAMETER(bool, allow_speculative_load_exec, true, "Allow loads to proceed speculatively before all older store addresses are known")
// Pipeline length
PARAMETER(uint32_t, mmu_lookup_stage_length, 1, "Length of the mmu lookup stage")
Expand All @@ -77,6 +74,7 @@ namespace olympia
static const char name[];



////////////////////////////////////////////////////////////////////////////////
// Type Name/Alias Declaration
////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -258,12 +256,6 @@ namespace olympia
LoadStoreIssueQueue ldst_inst_queue_;
const uint32_t ldst_inst_queue_size_;

sparta::Buffer<LoadStoreInstInfoPtr> load_queue_;
const uint32_t load_queue_size_;

sparta::Buffer<LoadStoreInstInfoPtr> store_queue_;
const uint32_t store_queue_size_;

sparta::Buffer<LoadStoreInstInfoPtr> replay_buffer_;
const uint32_t replay_buffer_size_;

Expand Down Expand Up @@ -303,7 +295,6 @@ namespace olympia
uint32_t COMPLETE = 4;

// LSU Microarchitecture parameters
const bool stall_pipeline_on_miss_;
const bool allow_speculative_load_exec_;

////////////////////////////////////////////////////////////////////////////////
Expand All @@ -317,9 +308,6 @@ namespace olympia
sparta::PayloadEvent<InstPtr> uev_replay_ready_{&unit_event_set_, "replay_ready",
CREATE_SPARTA_HANDLER_WITH_DATA(LSU, replayReady_, InstPtr)};

sparta::UniqueEvent<> uev_pipe_stall_{&unit_event_set_, "pipe_stall",
CREATE_SPARTA_HANDLER(LSU, pipeStall_)};

////////////////////////////////////////////////////////////////////////////////
// Callbacks
////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -359,9 +347,6 @@ namespace olympia
// Handle instruction flush in LSU
void handleFlush_(const FlushCriteria &);

// Perform pipeline stall
void pipeStall_();

// Instructions in the replay ready to issue
void replayReady_(const InstPtr &);

Expand Down
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ add_subdirectory(sim)
add_subdirectory(core/common)
add_subdirectory(core/dispatch)
add_subdirectory(core/rename)
add_subdirectory(core/lsu)
14 changes: 14 additions & 0 deletions test/core/lsu/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
project(Lsu_test)

target_link_libraries(core mss)

add_executable(Lsu_test Lsu_test.cpp ${SIM_BASE}/sim/OlympiaSim.cpp)

target_link_libraries (Lsu_test core common_test ${STF_LINK_LIBS} SPARTA::sparta)

file(CREATE_LINK ${SIM_BASE}/mavis/json ${CMAKE_CURRENT_BINARY_DIR}/mavis_isa_files SYMBOLIC)
file(CREATE_LINK ${SIM_BASE}/arches ${CMAKE_CURRENT_BINARY_DIR}/arches SYMBOLIC)
file(CREATE_LINK ${CMAKE_CURRENT_SOURCE_DIR}/test_cores ${CMAKE_CURRENT_BINARY_DIR}/test_cores SYMBOLIC)
file(CREATE_LINK ${CMAKE_CURRENT_SOURCE_DIR}/raw.json ${CMAKE_CURRENT_BINARY_DIR}/raw.json SYMBOLIC)

sparta_named_test(Lsu_test_raw Lsu_test small_core.out -c test_cores/test_small_core.yaml --input-file raw.json)
116 changes: 116 additions & 0 deletions test/core/lsu/Lsu_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@

#include "Dispatch.hpp"
#include "MavisUnit.hpp"
#include "CoreUtils.hpp"
#include "Rename.hpp"
#include "ExecutePipe.hpp"
#include "LSU.hpp"
#include "sim/OlympiaSim.hpp"
#include "OlympiaAllocators.hpp"

#include "test/core/common/SourceUnit.hpp"
#include "test/core/common/SinkUnit.hpp"
#include "test/core/rename/ROBSinkUnit.hpp"

#include "sparta/app/CommandLineSimulator.hpp"
#include "sparta/utils/SpartaTester.hpp"
#include "sparta/resources/Buffer.hpp"
#include "sparta/sparta.hpp"
#include "sparta/simulation/ClockManager.hpp"
#include "sparta/kernel/Scheduler.hpp"
#include "sparta/utils/SpartaTester.hpp"
#include "sparta/statistics/StatisticSet.hpp"
#include "sparta/report/Report.hpp"
#include "sparta/events/UniqueEvent.hpp"
#include "sparta/app/Simulation.hpp"
#include "sparta/utils/SpartaSharedPointer.hpp"

#include <memory>
#include <vector>
#include <cinttypes>
#include <sstream>
#include <initializer_list>

TEST_INIT

class olympia::LSUTester
{
public:
void test_dependent_lsu_instruction(olympia::LSU & lsu){
// testing RAW dependency for LSU
// we have an ADD instruction before we destination register 3
// and then a subsequent STORE instruction to register 3
// we can't STORE until the add instruction runs, so we test
// while the ADD instruction is running, the STORE instruction should NOT issue
EXPECT_TRUE(lsu.lsu_insts_issued_ == 0);
}

void test_inst_issue(olympia::LSU &lsu, int count){
EXPECT_EQUAL(lsu.lsu_insts_issued_, count);
}
};

const char USAGE[] =
"Usage:\n"
" \n"
"\n";

sparta::app::DefaultValues DEFAULTS;

// The main tester of Rename. The test is encapsulated in the
// parameter test_type of the Source unit.
void runTest(int argc, char **argv)
{
DEFAULTS.auto_summary_default = "off";
std::vector<std::string> datafiles;
std::string input_file;

sparta::app::CommandLineSimulator cls(USAGE, DEFAULTS);
auto & app_opts = cls.getApplicationOptions();
app_opts.add_options()
("output_file",
sparta::app::named_value<std::vector<std::string>>("output_file", &datafiles),
"Specifies the output file")
("input-file",
sparta::app::named_value<std::string>("INPUT_FILE", &input_file)->default_value(""),
"Provide a JSON instruction stream",
"Provide a JSON file with instructions to run through Execute");

po::positional_options_description& pos_opts = cls.getPositionalOptions();
pos_opts.add("output_file", -1); // example, look for the <data file> at the end

int err_code = 0;
if(!cls.parse(argc, argv, err_code)){
sparta_assert(false, "Command line parsing failed"); // Any errors already printed to cerr
}

sparta_assert(false == datafiles.empty(), "Need an output file as the last argument of the test");

sparta::Scheduler scheduler;
uint64_t ilimit = 0;
uint32_t num_cores = 1;
bool show_factories = false;
OlympiaSim sim("simple",
scheduler,
num_cores, // cores
input_file,
ilimit,
show_factories);

cls.populateSimulation(&sim);
sparta::RootTreeNode* root_node = sim.getRoot();

olympia::LSU *my_lsu = root_node->getChild("cpu.core0.lsu")->getResourceAs<olympia::LSU*>();
olympia::LSUTester lsupipe_tester;
cls.runSimulator(&sim, 7);
lsupipe_tester.test_inst_issue(*my_lsu, 2);
cls.runSimulator(&sim);
}

int main(int argc, char **argv)
{
runTest(argc, argv);

REPORT_ERROR;
return (int)ERROR_CODE;
}
Loading

0 comments on commit 7f2402b

Please sign in to comment.