1 Star 0 Fork 1

gdwindow/SweRV-ISS

forked from CHIPS-Alliance/SweRV-ISS 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
Server.cpp 22.07 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940
// Copyright 2020 Western Digital Corporation or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <iostream>
#include <sstream>
#include <map>
#include <algorithm>
#include <boost/format.hpp>
#include <cstring>
#ifdef __MINGW64__
#include <winsock2.h>
#else
#include <arpa/inet.h>
#include <sys/socket.h>
#endif
#define __STDC_FORMAT_MACROS
#include <cinttypes>
#include "WhisperMessage.h"
#include "Hart.hpp"
#include "Server.hpp"
using namespace WdRiscv;
/// Return format string suitable for printing an integer of type URV
/// in hexadecimal form.
template <typename URV>
static
const char*
getHexForm()
{
if (sizeof(URV) == 4)
return "0x%08x";
if (sizeof(URV) == 8)
return "0x%016x";
if (sizeof(URV) == 16)
return "0x%032x";
return "0x%x";
}
/// Unpack socket message (received in server mode) into the given
/// WhisperMessage object.
static
void
deserializeMessage(const char buffer[], size_t bufferLen,
WhisperMessage& msg)
{
assert (bufferLen >= sizeof(msg));
const char* p = buffer;
uint32_t x = ntohl(*((uint32_t*)p));
msg.hart = x;
p += sizeof(x);
x = ntohl(*((uint32_t*)p));
msg.type = x;
p += sizeof(x);
x = ntohl(*((uint32_t*)p));
msg.resource = x;
p += sizeof(x);
x = ntohl(*((uint32_t*)p));
msg.flags = x;
p += sizeof(x);
uint32_t part = ntohl(*((uint32_t*)p));
msg.rank = uint64_t(part) << 32;
p += sizeof(part);
part = ntohl(*(uint32_t*)p);
msg.rank |= part;
p += sizeof(part);
part = ntohl(*((uint32_t*)p));
msg.address = uint64_t(part) << 32;
p += sizeof(part);
part = ntohl(*((uint32_t*)p));
msg.address |= part;
p += sizeof(part);
part = ntohl(*((uint32_t*)p));
msg.value = uint64_t(part) << 32;
p += sizeof(part);
part = ntohl(*((uint32_t*)p));
msg.value |= part;
p += sizeof(part);
memcpy(msg.buffer, p, sizeof(msg.buffer));
p += sizeof(msg.buffer);
memcpy(msg.tag, p, sizeof(msg.tag));
p += sizeof(msg.tag);
assert(size_t(p - buffer) <= bufferLen);
}
/// Serialize the given WhisperMessage into the given buffer in
/// preparation for socket send. Return the number of bytes written
/// into buffer.
static
size_t
serializeMessage(const WhisperMessage& msg, char buffer[],
size_t bufferLen)
{
assert (bufferLen >= sizeof(msg));
char* p = buffer;
uint32_t x = htonl(msg.hart);
memcpy(p, &x, sizeof(x));
p += sizeof(x);
x = htonl(msg.type);
memcpy(p, &x, sizeof(x));
p += sizeof(x);
x = htonl(msg.resource);
memcpy(p, &x, sizeof(x));
p += sizeof(x);
x = htonl(msg.flags);
memcpy(p, &x, sizeof(x));
p += sizeof(x);
uint32_t part = static_cast<uint32_t>(msg.rank >> 32);
x = htonl(part);
memcpy(p, &x, sizeof(x));
p += sizeof(x);
part = (msg.rank) & 0xffffffff;
x = htonl(part);
memcpy(p, &x, sizeof(x));
p += sizeof(x);
part = static_cast<uint32_t>(msg.address >> 32);
x = htonl(part);
memcpy(p, &x, sizeof(x));
p += sizeof(x);
part = (msg.address) & 0xffffffff;
x = htonl(part);
memcpy(p, &x, sizeof(x));
p += sizeof(x);
part = static_cast<uint32_t>(msg.value >> 32);
x = htonl(part);
memcpy(p, &x, sizeof(x));
p += sizeof(x);
part = msg.value & 0xffffffff;
x = htonl(part);
memcpy(p, &x, sizeof(x));
p += sizeof(x);
memcpy(p, msg.buffer, sizeof(msg.buffer));
p += sizeof(msg.buffer);
memcpy(p, msg.tag, sizeof(msg.tag));
p += sizeof(msg.tag);
size_t len = p - buffer;
assert(len <= bufferLen);
assert(len <= sizeof(msg));
for (size_t i = len; i < sizeof(msg); ++i)
buffer[i] = 0;
return sizeof(msg);
}
static bool
receiveMessage(int soc, WhisperMessage& msg)
{
char buffer[sizeof(msg)];
char* p = buffer;
size_t remain = sizeof(msg);
while (remain > 0)
{
ssize_t l = recv(soc, p, remain, 0);
if (l < 0)
{
if (errno == EINTR)
continue;
std::cerr << "Failed to receive socket message\n";
return false;
}
if (l == 0)
{
msg.type = Quit;
return true;
}
remain -= l;
p += l;
}
deserializeMessage(buffer, sizeof(buffer), msg);
return true;
}
static bool
sendMessage(int soc, WhisperMessage& msg)
{
char buffer[sizeof(msg)];
serializeMessage(msg, buffer, sizeof(buffer));
// Send command.
ssize_t remain = sizeof(msg);
char* p = buffer;
while (remain > 0)
{
ssize_t l = send(soc, p, remain , 0);
if (l < 0)
{
if (errno == EINTR)
continue;
std::cerr << "Failed to send socket command\n";
return false;
}
remain -= l;
p += l;
}
return true;
}
template <typename URV>
Server<URV>::Server(System<URV>& system)
: system_(system)
{
}
template <typename URV>
bool
Server<URV>::pokeCommand(const WhisperMessage& req, WhisperMessage& reply)
{
reply = req;
if (not checkHartId(req, reply))
return false;
uint32_t hartId = req.hart;
auto hartPtr = system_.ithHart(hartId);
if (not hartPtr)
return false;
auto& hart = *hartPtr;
switch (req.resource)
{
case 'r':
{
unsigned reg = static_cast<unsigned>(req.address);
URV val = static_cast<URV>(req.value);
if (reg == req.address)
if (hart.pokeIntReg(reg, val))
return true;
}
break;
case 'c':
{
URV val = static_cast<URV>(req.value);
if (hart.pokeCsr(CsrNumber(req.address), val))
return true;
}
break;
case 'm':
if (sizeof(URV) == 4)
{
// Poke a word in 32-bit harts.
if (hart.pokeMemory(req.address, uint32_t(req.value)))
return true;
}
else if (hart.pokeMemory(req.address, req.value))
return true;
break;
}
reply.type = Invalid;
return false;
}
template <typename URV>
bool
Server<URV>::peekCommand(const WhisperMessage& req, WhisperMessage& reply)
{
reply = req;
if (not checkHartId(req, reply))
return false;
uint32_t hartId = req.hart;
auto hartPtr = system_.ithHart(hartId);
if (not hartPtr)
return false;
auto& hart = *hartPtr;
URV value;
switch (req.resource)
{
case 'r':
{
unsigned reg = static_cast<unsigned>(req.address);
if (reg == req.address)
if (hart.peekIntReg(reg, value))
{
reply.value = value;
return true;
}
}
break;
case 'f':
{
unsigned reg = static_cast<unsigned>(req.address);
uint64_t fpVal = 0;
if (reg == req.address)
if (hart.peekFpReg(reg, fpVal))
{
reply.value = fpVal;
return true;
}
}
break;
case 'c':
if (hart.peekCsr(CsrNumber(req.address), value))
{
reply.value = value;
return true;
}
break;
case 'm':
if (hart.peekMemory(req.address, value))
{
reply.value = value;
return true;
}
break;
}
reply.type = Invalid;
return true;
}
template <typename URV>
void
Server<URV>::disassembleAnnotateInst(Hart<URV>& hart,
uint32_t inst, bool interrupted,
bool hasPreTrigger, bool hasPostTrigger,
std::string& text)
{
hart.disassembleInst(inst, text);
uint32_t op0 = 0, op1 = 0, op2 = 0, op3 = 0;
const InstEntry& entry = hart.decode(inst, op0, op1, op2, op3);
if (entry.isBranch())
{
if (hart.lastPc() + instructionSize(inst) != hart.peekPc())
text += " (T)";
else
text += " (NT)";
}
if (not interrupted)
if (entry.isLoad() or entry.isStore() or entry.isAtomic())
{
URV addr = hart.lastLdStAddress();
std::ostringstream oss;
oss << " [0x" << std::hex << addr << "]" << std::dec;
text += oss.str();
}
if (interrupted)
text += " (interrupted)";
else if (hasPreTrigger)
text += " (pre-trigger)";
else if (hasPostTrigger)
text += " (post-trigger)";
}
template <typename URV>
void
Server<URV>::processStepCahnges(Hart<URV>& hart,
uint32_t inst,
std::vector<WhisperMessage>& pendingChanges,
bool interrupted, bool hasPre, bool hasPost,
WhisperMessage& reply)
{
// Get executed instruction.
URV pc = hart.lastPc();
// Add pc and instruction to reply.
reply.type = ChangeCount;
reply.address = pc;
reply.resource = inst;
// Add disassembly of instruction to reply.
std::string text;
disassembleAnnotateInst(hart, inst, interrupted, hasPre, hasPost, text);
strncpy(reply.buffer, text.c_str(), sizeof(reply.buffer) - 1);
reply.buffer[sizeof(reply.buffer) -1] = 0;
// Collect integer register change caused by execution of instruction.
pendingChanges.clear();
int regIx = hart.lastIntReg();
if (regIx > 0)
{
URV value = 0;
if (hart.peekIntReg(regIx, value))
{
WhisperMessage msg;
msg.type = Change;
msg.resource = 'r';
msg.address = regIx;
msg.value = value;
pendingChanges.push_back(msg);
}
}
// Collect floating point register change.
int fpRegIx = hart.lastFpReg();
if (fpRegIx >= 0)
{
uint64_t val = 0;
if (hart.peekFpReg(fpRegIx, val))
{
WhisperMessage msg;
msg.type = Change;
msg.resource = 'f';
msg.address = fpRegIx;
msg.value = val;
pendingChanges.push_back(msg);
}
}
// Collect CSR and trigger changes.
std::vector<CsrNumber> csrs;
std::vector<unsigned> triggers;
hart.lastCsr(csrs, triggers);
// Map to keep CSRs in order and to drop duplicate entries.
std::map<URV,URV> csrMap;
// Components of the triggers that changed (if any).
std::vector<bool> tdataChanged(3);
// Collect changed CSRs and their values. Collect components of
// changed trigger.
for (CsrNumber csr : csrs)
{
URV value;
if (hart.peekCsr(csr, value))
{
if (csr >= CsrNumber::TDATA1 and csr <= CsrNumber::TDATA3)
{
size_t ix = size_t(csr) - size_t(CsrNumber::TDATA1);
tdataChanged.at(ix) = true;
}
else
csrMap[URV(csr)] = value;
}
}
// Collect changes associated with trigger register.
for (unsigned trigger : triggers)
{
URV data1(0), data2(0), data3(0);
if (not hart.peekTrigger(trigger, data1, data2, data3))
continue;
if (tdataChanged.at(0))
{
URV addr = (trigger << 16) | unsigned(CsrNumber::TDATA1);
csrMap[addr] = data1;
}
if (tdataChanged.at(1))
{
URV addr = (trigger << 16) | unsigned(CsrNumber::TDATA2);
csrMap[addr] = data2;
}
if (tdataChanged.at(2))
{
URV addr = (trigger << 16) | unsigned(CsrNumber::TDATA3);
csrMap[addr] = data3;
}
}
for (const auto& [key, val] : csrMap)
{
WhisperMessage msg(0, Change, 'c', key, val);
pendingChanges.push_back(msg);
}
std::vector<size_t> addresses;
std::vector<uint32_t> words;
hart.lastMemory(addresses, words);
assert(addresses.size() == words.size());
for (size_t i = 0; i < addresses.size(); ++i)
{
WhisperMessage msg(0, Change, 'm', addresses.at(i), words.at(i));
pendingChanges.push_back(msg);
}
// Add count of changes to reply.
reply.value = pendingChanges.size();
// The changes will be retrieved one at a time from the back of the
// pendigChanges vector: Put the vector in reverse order. Changes
// are retrieved using a Change request (see interactUsingSocket).
std::reverse(pendingChanges.begin(), pendingChanges.end());
}
template <typename URV>
bool
Server<URV>::checkHartId(const WhisperMessage& req, WhisperMessage& reply)
{
uint32_t hartId = req.hart;
if (hartId >= system_.hartCount())
{
std::cerr << "Error: Hart ID (" << std::dec << hartId
<< ") out of bounds\n";
reply.type = Invalid;
return false;
}
return true;
}
template <typename URV>
bool
Server<URV>::checkHart(const WhisperMessage& req, const std::string& command,
WhisperMessage& reply)
{
if (not checkHartId(req, reply))
return false;
uint32_t hartId = req.hart;
auto hartPtr = system_.ithHart(hartId);
if (not hartPtr)
return false;
auto& hart = *hartPtr;
if (not hart.isStarted())
{
std::cerr << "Error: Command " << command
<< " received for a non-started hart\n";
reply.type = Invalid;
return false;
}
return true;
}
// Server mode step command.
template <typename URV>
bool
Server<URV>::stepCommand(const WhisperMessage& req,
std::vector<WhisperMessage>& pendingChanges,
WhisperMessage& reply,
FILE* traceFile)
{
reply = req;
// Hart id must be valid. Hart must be started.
if (not checkHart(req, "step", reply))
return false;
uint32_t hartId = req.hart;
auto hartPtr = system_.ithHart(hartId);
if (not hartPtr)
return false;
auto& hart = *hartPtr;
// Step is not allowed in debug mode unless we are in debug_step as
// well.
if (hart.inDebugMode() and not hart.inDebugStepMode())
{
std::cerr << "Error: Single step while in debug-halt mode\n";
reply.type = Invalid;
return false;
}
// Get instruction before execution (in case code is self-modifying).
uint32_t inst = 0;
hart.readInst(hart.peekPc(), inst);
// Get privilege mode.
int privMode = int(hart.privilegeMode());
// Execute instruction. Determine if an interrupt was taken or if a
// trigger got tripped.
uint64_t interruptCount = hart.getInterruptCount();
hart.singleStep(traceFile);
bool interrupted = hart.getInterruptCount() != interruptCount;
unsigned preCount = 0, postCount = 0;
hart.countTrippedTriggers(preCount, postCount);
bool hasPre = preCount > 0;
bool hasPost = postCount > 0;
processStepCahnges(hart, inst, pendingChanges, interrupted, hasPre,
hasPost, reply);
reply.flags = privMode;
hart.clearTraceData();
return true;
}
// Server mode exception command.
template <typename URV>
bool
Server<URV>::exceptionCommand(const WhisperMessage& req,
WhisperMessage& reply,
std::string& text)
{
reply = req;
if (not checkHart(req, "exception", reply))
return false;
uint32_t hartId = req.hart;
auto hartPtr = system_.ithHart(hartId);
if (not hartPtr)
return false;
auto& hart = *hartPtr;
std::ostringstream oss;
bool ok = true;
URV addr = static_cast<URV>(req.address);
if (addr != req.address)
std::cerr << "Error: Address too large (" << std::hex << req.address
<< ") in exception command.\n" << std::dec;
WhisperExceptionType expType = WhisperExceptionType(req.value);
switch (expType)
{
case InstAccessFault:
hart.postInstAccessFault(addr);
oss << "exception inst " << addr;
break;
case DataAccessFault:
hart.postDataAccessFault(addr, SecondaryCause::LOAD_ACC_DOUBLE_ECC);
oss << "exception data " << addr;
break;
case ImpreciseStoreFault:
{
unsigned count = 0;
ok = hart.applyStoreException(addr, count);
reply.value = count;
}
oss << "exception store 0x" << std::hex << addr << std::dec;
break;
case ImpreciseLoadFault:
{
unsigned tag = reply.flags; // Tempoary.
unsigned count = 0;
ok = hart.applyLoadException(addr, tag, count);
reply.value = count;
oss << "exception load 0x" << std::hex << addr << std::dec << ' '
<< tag;
}
break;
case NonMaskableInterrupt:
if (hart.isNmiEnabled())
hart.setPendingNmi(NmiCause(addr));
oss << "exception nmi 0x" << std::hex << addr << std::dec;
break;
case PreciseLoadFault:
oss << "exception precise_load 0x" << std::hex << addr << std::dec;
hart.postDataAccessFault(addr, SecondaryCause::LOAD_ACC_PRECISE);
ok = false;
break;
case PreciseStoreFault:
hart.postDataAccessFault(addr, SecondaryCause::STORE_ACC_PRECISE);
oss << "exception precise_store 0x" << std::hex << addr << std::dec;
ok = false;
break;
default:
oss << "exception ? 0x" << std::hex << addr << std::dec;
ok = false;
break;
}
if (not ok)
reply.type = Invalid;
text = oss.str();
return ok;
}
// Server mode loop: Receive command and send reply till a quit
// command is received. Return true on successful termination (quit
// received). Return false otherwise.
template <typename URV>
bool
Server<URV>::interact(int soc, FILE* traceFile, FILE* commandLog)
{
std::vector<WhisperMessage> pendingChanges;
auto hexForm = getHexForm<URV>(); // Format string for printing a hex val
// Initial resets do not reset memory mapped registers.
bool resetMemoryMappedReg = false;
while (true)
{
WhisperMessage msg;
if (not receiveMessage(soc, msg))
return false;
WhisperMessage reply = msg;
if (checkHartId(msg, reply))
{
std::string timeStamp = std::to_string(msg.rank);
uint32_t hartId = msg.hart;
auto hartPtr = system_.ithHart(hartId);
assert(hartPtr);
auto& hart = *hartPtr;
if (msg.type == Step or msg.type == Until)
resetMemoryMappedReg = true;
switch (msg.type)
{
case Quit:
if (commandLog)
fprintf(commandLog, "hart=%d quit\n", hartId);
return true;
case Poke:
pokeCommand(msg, reply);
if (commandLog)
fprintf(commandLog, "hart=%d poke %c %s %s # ts=%s tag=%s\n", hartId,
msg.resource,
(boost::format(hexForm) % msg.address).str().c_str(),
(boost::format(hexForm) % msg.value).str().c_str(),
timeStamp.c_str(), msg.tag);
break;
case Peek:
peekCommand(msg, reply);
if (commandLog)
fprintf(commandLog, "hart=%d peek %c %s # ts=%s\n", hartId,
msg.resource,
(boost::format(hexForm) % msg.address).str().c_str(),
timeStamp.c_str());
break;
case Step:
stepCommand(msg, pendingChanges, reply, traceFile);
if (commandLog)
fprintf(commandLog, "hart=%d step #%" PRId64 " # ts=%s\n",
hartId, hart.getInstructionCount(), timeStamp.c_str());
break;
case ChangeCount:
reply.type = ChangeCount;
reply.value = pendingChanges.size();
reply.address = hart.lastPc();
{
uint32_t inst = 0;
hart.readInst(hart.lastPc(), inst);
reply.resource = inst;
std::string text;
hart.disassembleInst(inst, text);
uint32_t op0 = 0, op1 = 0, op2 = 0, op3 = 0;
const InstEntry& entry = hart.decode(inst, op0, op1, op2, op3);
if (entry.isBranch())
{
if (hart.lastPc() + instructionSize(inst) != hart.peekPc())
text += " (T)";
else
text += " (NT)";
}
strncpy(reply.buffer, text.c_str(), sizeof(reply.buffer) - 1);
reply.buffer[sizeof(reply.buffer) -1] = 0;
}
break;
case Change:
if (pendingChanges.empty())
reply.type = Invalid;
else
{
reply = pendingChanges.back();
pendingChanges.pop_back();
}
break;
case Reset:
{
URV addr = static_cast<URV>(msg.address);
if (addr != msg.address)
std::cerr << "Error: Address too large (" << std::hex
<< msg.address << ") in reset command.\n" << std::dec;
pendingChanges.clear();
if (msg.value != 0)
hart.defineResetPc(addr);
hart.reset(resetMemoryMappedReg);
if (commandLog)
{
if (msg.value != 0)
fprintf(commandLog, "hart=%d reset %s # ts=%s\n", hartId,
(boost::format(hexForm) % addr).str().c_str(),
timeStamp.c_str());
else
fprintf(commandLog, "hart=%d reset # ts=%s\n", hartId,
timeStamp.c_str());
}
}
break;
case Exception:
{
std::string text;
exceptionCommand(msg, reply, text);
if (commandLog)
fprintf(commandLog, "hart=%d %s # ts=%s\n", hartId,
text.c_str(), timeStamp.c_str());
}
break;
case EnterDebug:
if (checkHart(msg, "enter_debug", reply))
hart.enterDebugMode(hart.peekPc());
if (commandLog)
fprintf(commandLog, "hart=%d enter_debug # ts=%s\n", hartId,
timeStamp.c_str());
break;
case ExitDebug:
if (checkHart(msg, "exit_debug", reply))
hart.exitDebugMode();
if (commandLog)
fprintf(commandLog, "hart=%d exit_debug # ts=%s\n", hartId,
timeStamp.c_str());
break;
case LoadFinished:
{
URV addr = static_cast<URV>(msg.address);
unsigned tag = msg.flags;
if (checkHart(msg, "load_finished", reply))
{
if (addr != msg.address)
std::cerr << "Error: Address too large (" << std::hex
<< msg.address << ") in load finished command.\n"
<< std::dec;
unsigned matchCount = 0;
hart.applyLoadFinished(addr, tag, matchCount);
reply.value = matchCount;
}
if (commandLog)
fprintf(commandLog, "hart=%d load_finished 0x%0*" PRIx64 " %d # ts=%s\n",
hartId,
( (sizeof(URV) == 4) ? 8 : 16 ), uint64_t(addr),
tag, timeStamp.c_str());
}
break;
case CancelDiv:
if (checkHart(msg, "cancel_div", reply))
if (not hart.cancelLastDiv())
reply.type = Invalid;
if (commandLog)
fprintf(commandLog, "hart=%d cancel_div # ts=%s\n", hartId,
timeStamp.c_str());
break;
case CancelLr:
if (checkHart(msg, "cancel_lr", reply))
hart.cancelLr();
if (commandLog)
fprintf(commandLog, "hart=%d cancel_lr # ts=%s\n", hartId,
timeStamp.c_str());
break;
default:
std::cerr << "Unknown command\n";
reply.type = Invalid;
}
}
if (not sendMessage(soc, reply))
return false;
}
return false;
}
template class WdRiscv::Server<uint32_t>;
template class WdRiscv::Server<uint64_t>;
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/gdwindow/SweRV-ISS.git
git@gitee.com:gdwindow/SweRV-ISS.git
gdwindow
SweRV-ISS
SweRV-ISS
master

搜索帮助