Add float to int conversion directives, some misc changes (#3847)

* Add fptoi and itofp dirs

* Fix F32 literal

* Add some file read stage telemetry to err msgs

* Update default register count to 128

* Fix NOT directive to behave properly with if

* Make fptoi and itofp signed/unsigned

* fix warning

* Fix another warning

* Fix sp
This commit is contained in:
Zimri Leisher 2025-07-13 13:22:33 -05:00 committed by GitHub
parent 2690e31bff
commit a91f24cb38
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 243 additions and 87 deletions

View File

@ -244,11 +244,14 @@ fpptest
fprime
fptr
fptrunc
fptosi
fptoui
fputil
fpy
FPYSEQUENCER
freeram
Fregoso
fres
frhs
frsize
fsblkcnt
@ -599,6 +602,7 @@ sideeffect
sighandler
Signedness
Silveira
sitofp
sle
sloc
socio
@ -696,6 +700,7 @@ typedef
uart
UDPSOCKET
uge
uitofp
ulhs
UML
UNEXP

View File

@ -13,6 +13,12 @@ module Svc {
IDLE
}
enum FileReadStage {
HEADER
BODY
FOOTER
}
include "FpySequencerCommands.fppi"
include "FpySequencerTelemetry.fppi"
include "FpySequencerEvents.fppi"

View File

@ -23,8 +23,7 @@
static_assert(Svc::Fpy::MAX_SEQUENCE_ARG_COUNT <= std::numeric_limits<U8>::max(),
"Sequence arg count must be below U8 max");
static_assert(Svc::Fpy::NUM_REGISTERS <= std::numeric_limits<U8>::max(),
"Register count must be below U8 max");
static_assert(Svc::Fpy::NUM_REGISTERS <= std::numeric_limits<U8>::max(), "Register count must be below U8 max");
static_assert(Svc::Fpy::MAX_SEQUENCE_STATEMENT_COUNT <= std::numeric_limits<U16>::max(),
"Sequence statement count must be below U16 max");
static_assert(Svc::Fpy::MAX_SERIALIZABLE_REGISTER_SIZE <= std::numeric_limits<FwSizeType>::max(),
@ -41,8 +40,7 @@ using State = FpySequencer_SequencerStateMachineStateMachineBase::State;
using DirectiveError = FpySequencer_DirectiveErrorCode;
class FpySequencer : public FpySequencerComponentBase {
friend class FpySequencerTester;
friend class FpySequencerTester;
public:
union DirectiveUnion {
@ -78,17 +76,15 @@ class FpySequencer : public FpySequencerComponentBase {
//!
~FpySequencer();
private:
//! Handler for command RUN
//!
//! Loads, validates and runs a sequence
void
RUN_cmdHandler(FwOpcodeType opCode, //!< The opcode
U32 cmdSeq, //!< The command sequence number
const Fw::CmdStringArg& fileName, //!< The name of the sequence file
FpySequencer_BlockState block //!< Return command status when complete or not
) override;
private:
//! Handler for command RUN
//!
//! Loads, validates and runs a sequence
void RUN_cmdHandler(FwOpcodeType opCode, //!< The opcode
U32 cmdSeq, //!< The command sequence number
const Fw::CmdStringArg& fileName, //!< The name of the sequence file
FpySequencer_BlockState block //!< Return command status when complete or not
) override;
//! Handler for command VALIDATE
//!
@ -323,32 +319,30 @@ class FpySequencer : public FpySequencerComponentBase {
//!
//! called when a sequence failed to execute successfully
void Svc_FpySequencer_SequencerStateMachine_action_report_seqFailed(
SmId smId, //!< The state machine id
Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
) override;
SmId smId, //!< The state machine id
Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
) override;
//! Implementation for action report_seqStarted of state machine Svc_FpySequencer_SequencerStateMachine
//!
//! reports that a sequence was started
void Svc_FpySequencer_SequencerStateMachine_action_report_seqStarted(
SmId smId, //!< The state machine id
Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
) override;
SmId smId, //!< The state machine id
Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
) override;
protected:
protected:
// ----------------------------------------------------------------------
// Functions to implement for internal state machine guards
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// Functions to implement for internal state machine guards
// ----------------------------------------------------------------------
//! Implementation for guard goalStateIs_RUNNING of state machine Svc_FpySequencer_SequencerStateMachine
//!
//! return true if the goal state is RUNNING
bool
Svc_FpySequencer_SequencerStateMachine_guard_goalStateIs_RUNNING(
SmId smId, //!< The state machine id
Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
) const override;
//! Implementation for guard goalStateIs_RUNNING of state machine Svc_FpySequencer_SequencerStateMachine
//!
//! return true if the goal state is RUNNING
bool Svc_FpySequencer_SequencerStateMachine_guard_goalStateIs_RUNNING(
SmId smId, //!< The state machine id
Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
) const override;
//! Implementation for guard shouldDebugBreak of state machine Svc_FpySequencer_SequencerStateMachine
//!
@ -384,9 +378,7 @@ class FpySequencer : public FpySequencerComponentBase {
) override;
//! Handler for input port seqRunIn
void seqRunIn_handler(FwIndexType portNum,
const Fw::StringBase& filename
) override;
void seqRunIn_handler(FwIndexType portNum, const Fw::StringBase& filename) override;
//! Handler for input port pingIn
void pingIn_handler(FwIndexType portNum, //!< The port number
@ -426,13 +418,15 @@ class FpySequencer : public FpySequencerComponentBase {
void directive_cmd_internalInterfaceHandler(const Svc::FpySequencer_CmdDirective& directive) override;
//! Internal interface handler for directive_deserSerReg
void directive_deserSerReg_internalInterfaceHandler(const Svc::FpySequencer_DeserSerRegDirective& directive) override;
void directive_deserSerReg_internalInterfaceHandler(
const Svc::FpySequencer_DeserSerRegDirective& directive) override;
//! Internal interface handler for directive_setReg
void directive_setReg_internalInterfaceHandler(const Svc::FpySequencer_SetRegDirective& directive) override;
//! Internal interface handler for directive_binaryRegOp
void directive_binaryRegOp_internalInterfaceHandler(const Svc::FpySequencer_BinaryRegOpDirective& directive) override;
void directive_binaryRegOp_internalInterfaceHandler(
const Svc::FpySequencer_BinaryRegOpDirective& directive) override;
//! Internal interface handler for directive_unaryRegOp
void directive_unaryRegOp_internalInterfaceHandler(const Svc::FpySequencer_UnaryRegOpDirective& directive) override;
@ -447,9 +441,9 @@ class FpySequencer : public FpySequencerComponentBase {
void allocateBuffer(FwEnumStoreType identifier, Fw::MemAllocator& allocator, FwSizeType bytes);
void deallocateBuffer(Fw::MemAllocator& allocator);
private :
static constexpr U32 CRC_INITIAL_VALUE = 0xFFFFFFFFU;
private:
static constexpr U32 CRC_INITIAL_VALUE = 0xFFFFFFFFU;
// allocated at startup
Fw::ExternalSerializeBuffer m_sequenceBuffer;
@ -570,7 +564,10 @@ class FpySequencer : public FpySequencerComponentBase {
// updates the CRC by default, but can be turned off if the contents
// aren't included in CRC.
// return success if successful
Fw::Success readBytes(Os::File& file, FwSizeType readLen, bool updateCrc = true);
Fw::Success readBytes(Os::File& file,
FwSizeType readLen,
const FpySequencer_FileReadStage& readStage,
bool updateCrc = true);
// ----------------------------------------------------------------------
// Run state
@ -648,6 +645,10 @@ class FpySequencer : public FpySequencerComponentBase {
I64 unaryRegOp_not(I64 src);
I64 unaryRegOp_fpext(I64 src);
I64 unaryRegOp_fptrunc(I64 src);
I64 unaryRegOp_fptoui(I64 src);
I64 unaryRegOp_fptosi(I64 src);
I64 unaryRegOp_sitofp(I64 src);
I64 unaryRegOp_uitofp(I64 src);
Signal exit_directiveHandler(const FpySequencer_ExitDirective& directive, DirectiveError& error);
};

View File

@ -111,15 +111,16 @@ void FpySequencer::directive_setReg_internalInterfaceHandler(const Svc::FpySeque
}
//! Internal interface handler for directive_binaryRegOp
void FpySequencer::directive_binaryRegOp_internalInterfaceHandler(const Svc::FpySequencer_BinaryRegOpDirective& directive) {
void FpySequencer::directive_binaryRegOp_internalInterfaceHandler(
const Svc::FpySequencer_BinaryRegOpDirective& directive) {
DirectiveError error = DirectiveError::NO_ERROR;
this->sendSignal(this->binaryRegOp_directiveHandler(directive, error));
this->m_tlm.lastDirectiveError = error;
}
//! Internal interface handler for directive_unaryRegOp
void FpySequencer::directive_unaryRegOp_internalInterfaceHandler(const Svc::FpySequencer_UnaryRegOpDirective& directive) {
void FpySequencer::directive_unaryRegOp_internalInterfaceHandler(
const Svc::FpySequencer_UnaryRegOpDirective& directive) {
DirectiveError error = DirectiveError::NO_ERROR;
this->sendSignal(this->unaryRegOp_directiveHandler(directive, error));
this->m_tlm.lastDirectiveError = error;
@ -488,7 +489,7 @@ I64 FpySequencer::binaryRegOp_fge(I64 lhs, I64 rhs) {
}
Signal FpySequencer::binaryRegOp_directiveHandler(const FpySequencer_BinaryRegOpDirective& directive,
DirectiveError& error) {
DirectiveError& error) {
// coding error, should not have gotten to this binary reg op handler
FW_ASSERT(directive.get_op() >= Fpy::DirectiveId::OR && directive.get_op() <= Fpy::DirectiveId::FGE,
static_cast<FwAssertArgType>(directive.get_op()));
@ -565,7 +566,10 @@ Signal FpySequencer::binaryRegOp_directiveHandler(const FpySequencer_BinaryRegOp
return Signal::stmtResponse_success;
}
I64 FpySequencer::unaryRegOp_not(I64 src) {
return ~src;
if (src) {
return static_cast<I64>(false);
}
return static_cast<I64>(true);
}
I64 FpySequencer::unaryRegOp_fpext(I64 src) {
// convert F32 to F64
@ -594,10 +598,41 @@ I64 FpySequencer::unaryRegOp_fptrunc(I64 src) {
// then extend to I64
return static_cast<I64>(itrunc);
}
Signal FpySequencer::unaryRegOp_directiveHandler(const FpySequencer_UnaryRegOpDirective& directive, DirectiveError& error) {
I64 FpySequencer::unaryRegOp_fptosi(I64 src) {
// first interpret as F64
F64 fsrc;
memcpy(&fsrc, &src, sizeof(fsrc));
// then static cast to int
return static_cast<I64>(fsrc);
}
I64 FpySequencer::unaryRegOp_sitofp(I64 src) {
// first static cast to float
F64 fsrc = static_cast<F64>(src);
// then return bits as I64
I64 res;
memcpy(&res, &fsrc, sizeof(res));
return res;
}
I64 FpySequencer::unaryRegOp_fptoui(I64 src) {
// first interpret as F64
F64 fsrc;
memcpy(&fsrc, &src, sizeof(fsrc));
// then static cast to unsigned int
// then return as a signed int
return static_cast<I64>(static_cast<U64>(fsrc));
}
I64 FpySequencer::unaryRegOp_uitofp(I64 src) {
// first static cast to unsigned, then to float
F64 fsrc = static_cast<F64>(static_cast<U64>(src));
// then return bits as I64
I64 res;
memcpy(&res, &fsrc, sizeof(res));
return res;
}
Signal FpySequencer::unaryRegOp_directiveHandler(const FpySequencer_UnaryRegOpDirective& directive,
DirectiveError& error) {
// coding error, should not have gotten to this unary reg op handler
FW_ASSERT(directive.get_op() >= Fpy::DirectiveId::NOT && directive.get_op() <= Fpy::DirectiveId::FPTRUNC,
FW_ASSERT(directive.get_op() >= Fpy::DirectiveId::NOT && directive.get_op() <= Fpy::DirectiveId::UITOFP,
static_cast<FwAssertArgType>(directive.get_op()));
if (directive.getsrc() >= Fpy::NUM_REGISTERS || directive.getres() >= Fpy::NUM_REGISTERS) {
@ -607,7 +642,7 @@ Signal FpySequencer::unaryRegOp_directiveHandler(const FpySequencer_UnaryRegOpDi
I64 src = reg(directive.getsrc());
I64& res = reg(directive.getres());
switch (directive.get_op()) {
case Fpy::DirectiveId::NOT:
res = this->unaryRegOp_not(src);
@ -618,6 +653,18 @@ Signal FpySequencer::unaryRegOp_directiveHandler(const FpySequencer_UnaryRegOpDi
case Fpy::DirectiveId::FPTRUNC:
res = this->unaryRegOp_fptrunc(src);
break;
case Fpy::DirectiveId::FPTOSI:
res = this->unaryRegOp_fptosi(src);
break;
case Fpy::DirectiveId::FPTOUI:
res = this->unaryRegOp_fptoui(src);
break;
case Fpy::DirectiveId::SITOFP:
res = this->unaryRegOp_sitofp(src);
break;
case Fpy::DirectiveId::UITOFP:
res = this->unaryRegOp_uitofp(src);
break;
default:
FW_ASSERT(0, directive.get_op());
break;

View File

@ -1,6 +1,6 @@
event InvalidCommand($state: I32) \
severity warning high \
format "Cannot run command in state {}"
format "Cannot execute command in state {}"
event InvalidSeqRunCall($state: I32) \
severity warning high \
@ -14,26 +14,29 @@ event FileOpenError(
format "File open error encountered while opening {}: {}"
event FileReadError(
readStage: FileReadStage
filePath: string
errorCode: I32
) \
severity warning high \
format "File read error encountered while reading {}: {}"
format "File read error encountered while reading {} of file {}: {}"
event EndOfFileError(
readStage: FileReadStage
filePath: string
) \
severity warning high \
format "End of file encountered unexpectedly while reading {}"
format "End of file encountered unexpectedly while reading {} of file {}"
event FileReadDeserializeError(
readStage: FileReadStage
filePath: string
errorCode: I32
buffLeft: U64
buffLength: U64
) \
severity warning high \
format "Deserialize error encountered while reading {}: {} ({} bytes left out of {})"
format "Deserialize error encountered while reading {} of file {}: {} ({} bytes left out of {})"
event WrongSchemaVersion(
expected: U8

View File

@ -332,7 +332,11 @@ Fw::Success FpySequencer::deserializeDirective(const Fpy::Statement& stmt, Direc
// fallthrough on purpose
case Fpy::DirectiveId::NOT:
case Fpy::DirectiveId::FPEXT:
case Fpy::DirectiveId::FPTRUNC: {
case Fpy::DirectiveId::FPTRUNC:
case Fpy::DirectiveId::FPTOSI:
case Fpy::DirectiveId::FPTOUI:
case Fpy::DirectiveId::SITOFP:
case Fpy::DirectiveId::UITOFP: {
new (&deserializedDirective.unaryRegOp) FpySequencer_UnaryRegOpDirective();
U8 src;
@ -456,7 +460,11 @@ void FpySequencer::dispatchDirective(const DirectiveUnion& directive, const Fpy:
// fallthrough on purpose
case Fpy::DirectiveId::NOT:
case Fpy::DirectiveId::FPEXT:
case Fpy::DirectiveId::FPTRUNC: {
case Fpy::DirectiveId::FPTRUNC:
case Fpy::DirectiveId::FPTOSI:
case Fpy::DirectiveId::FPTOUI:
case Fpy::DirectiveId::SITOFP:
case Fpy::DirectiveId::UITOFP: {
this->directive_unaryRegOp_internalInterfaceInvoke(directive.unaryRegOp);
return;
}

View File

@ -49,11 +49,18 @@ module Svc {
# unary reg op dirs
NOT = 33
# floating point extension and truncation
FPEXT = 34
FPTRUNC = 35
# floating point conversion to signed/unsigned integer,
# and vice versa
FPTOSI = 36
FPTOUI = 37
SITOFP = 38
UITOFP = 39
# end unary reg op dirs
EXIT = 36
EXIT = 40
}
struct Header {

View File

@ -48,7 +48,8 @@ Fw::Success FpySequencer::validate() {
return Fw::Success::FAILURE;
}
Fw::Success readStatus = this->readBytes(sequenceFile, Fpy::Header::SERIALIZED_SIZE);
Fw::Success readStatus =
this->readBytes(sequenceFile, Fpy::Header::SERIALIZED_SIZE, FpySequencer_FileReadStage::HEADER);
if (readStatus != Fw::Success::SUCCESS) {
return Fw::Success::FAILURE;
@ -60,7 +61,8 @@ Fw::Success FpySequencer::validate() {
return Fw::Success::FAILURE;
}
readStatus = readBytes(sequenceFile, this->m_sequenceObj.getheader().getbodySize());
readStatus =
readBytes(sequenceFile, this->m_sequenceObj.getheader().getbodySize(), FpySequencer_FileReadStage::BODY);
if (readStatus != Fw::Success::SUCCESS) {
return Fw::Success::FAILURE;
@ -73,7 +75,7 @@ Fw::Success FpySequencer::validate() {
}
// read footer bytes but don't include in CRC
readStatus = this->readBytes(sequenceFile, Fpy::Footer::SERIALIZED_SIZE, false);
readStatus = this->readBytes(sequenceFile, Fpy::Footer::SERIALIZED_SIZE, FpySequencer_FileReadStage::FOOTER, false);
if (readStatus != Fw::Success::SUCCESS) {
return Fw::Success::FAILURE;
@ -104,9 +106,9 @@ Fw::Success FpySequencer::readHeader() {
// deser header
Fw::SerializeStatus deserStatus = this->m_sequenceBuffer.deserialize(this->m_sequenceObj.getheader());
if (deserStatus != Fw::SerializeStatus::FW_SERIALIZE_OK) {
this->log_WARNING_HI_FileReadDeserializeError(this->m_sequenceFilePath, static_cast<I32>(deserStatus),
this->m_sequenceBuffer.getBuffLeft(),
this->m_sequenceBuffer.getBuffLength());
this->log_WARNING_HI_FileReadDeserializeError(
FpySequencer_FileReadStage::HEADER, this->m_sequenceFilePath, static_cast<I32>(deserStatus),
this->m_sequenceBuffer.getBuffLeft(), this->m_sequenceBuffer.getBuffLength());
return Fw::Success::FAILURE;
}
@ -140,9 +142,9 @@ Fw::Success FpySequencer::readBody() {
// TODO should probably check that this serReg is inside range
deserStatus = this->m_sequenceBuffer.deserialize(this->m_sequenceObj.getargs()[argMappingIdx]);
if (deserStatus != Fw::FW_SERIALIZE_OK) {
this->log_WARNING_HI_FileReadDeserializeError(this->m_sequenceFilePath, static_cast<I32>(deserStatus),
this->m_sequenceBuffer.getBuffLeft(),
this->m_sequenceBuffer.getBuffLength());
this->log_WARNING_HI_FileReadDeserializeError(
FpySequencer_FileReadStage::BODY, this->m_sequenceFilePath, static_cast<I32>(deserStatus),
this->m_sequenceBuffer.getBuffLeft(), this->m_sequenceBuffer.getBuffLength());
return Fw::Success::FAILURE;
}
}
@ -152,9 +154,9 @@ Fw::Success FpySequencer::readBody() {
// deser statement
deserStatus = this->m_sequenceBuffer.deserialize(this->m_sequenceObj.getstatements()[statementIdx]);
if (deserStatus != Fw::FW_SERIALIZE_OK) {
this->log_WARNING_HI_FileReadDeserializeError(this->m_sequenceFilePath, static_cast<I32>(deserStatus),
this->m_sequenceBuffer.getBuffLeft(),
this->m_sequenceBuffer.getBuffLength());
this->log_WARNING_HI_FileReadDeserializeError(
FpySequencer_FileReadStage::BODY, this->m_sequenceFilePath, static_cast<I32>(deserStatus),
this->m_sequenceBuffer.getBuffLeft(), this->m_sequenceBuffer.getBuffLength());
return Fw::Success::FAILURE;
}
}
@ -164,9 +166,9 @@ Fw::Success FpySequencer::readBody() {
Fw::Success FpySequencer::readFooter() {
Fw::SerializeStatus deserStatus = this->m_sequenceBuffer.deserialize(this->m_sequenceObj.getfooter());
if (deserStatus != Fw::FW_SERIALIZE_OK) {
this->log_WARNING_HI_FileReadDeserializeError(this->m_sequenceFilePath, static_cast<I32>(deserStatus),
this->m_sequenceBuffer.getBuffLeft(),
this->m_sequenceBuffer.getBuffLength());
this->log_WARNING_HI_FileReadDeserializeError(
FpySequencer_FileReadStage::FOOTER, this->m_sequenceFilePath, static_cast<I32>(deserStatus),
this->m_sequenceBuffer.getBuffLeft(), this->m_sequenceBuffer.getBuffLength());
return Fw::Success::FAILURE;
}
@ -183,7 +185,10 @@ Fw::Success FpySequencer::readFooter() {
// reads some bytes from the open file into the m_sequenceBuffer.
// return success if successful
Fw::Success FpySequencer::readBytes(Os::File& file, FwSizeType expectedReadLen, bool updateCrc) {
Fw::Success FpySequencer::readBytes(Os::File& file,
FwSizeType expectedReadLen,
const FpySequencer_FileReadStage& readStage,
bool updateCrc) {
FW_ASSERT(file.isOpen());
// this has to be declared a var because file.read must take a ref
FwSizeType actualReadLen = expectedReadLen;
@ -200,12 +205,12 @@ Fw::Success FpySequencer::readBytes(Os::File& file, FwSizeType expectedReadLen,
Os::File::Status fileStatus = file.read(this->m_sequenceBuffer.getBuffAddr(), actualReadLen);
if (fileStatus != Os::File::OP_OK) {
this->log_WARNING_HI_FileReadError(this->m_sequenceFilePath, static_cast<I32>(fileStatus));
this->log_WARNING_HI_FileReadError(readStage, this->m_sequenceFilePath, static_cast<I32>(fileStatus));
return Fw::Success::FAILURE;
}
if (actualReadLen < expectedReadLen) {
this->log_WARNING_HI_EndOfFileError(this->m_sequenceFilePath);
this->log_WARNING_HI_EndOfFileError(readStage, this->m_sequenceFilePath);
return Fw::Success::FAILURE;
}

View File

@ -691,12 +691,12 @@ TEST_F(FpySequencerTester, setReg) {
TEST_F(FpySequencerTester, unaryRegOp) {
// Test NOT
FpySequencer_UnaryRegOpDirective directiveNOT(0, 1, Fpy::DirectiveId::NOT);
tester_get_m_runtime_ptr()->regs[0] = 10;
tester_get_m_runtime_ptr()->regs[0] = true;
DirectiveError err = DirectiveError::NO_ERROR;
Signal result = tester_unaryRegOp_directiveHandler(directiveNOT, err);
ASSERT_EQ(result, Signal::stmtResponse_success);
ASSERT_EQ(err, DirectiveError::NO_ERROR);
ASSERT_EQ(tester_get_m_runtime_ptr()->regs[1], ~10);
ASSERT_EQ(tester_get_m_runtime_ptr()->regs[1], false);
// Test out-of-bounds register index
FpySequencer_UnaryRegOpDirective directiveOOB(Fpy::NUM_REGISTERS, 1, Fpy::DirectiveId::FPEXT);
@ -711,7 +711,7 @@ TEST_F(FpySequencerTester, unaryRegOp) {
TEST_F(FpySequencerTester, not) {
ASSERT_EQ(tester_unaryRegOp_not(0x123), ~0x123);
ASSERT_EQ(tester_unaryRegOp_not(true), false);
}
TEST_F(FpySequencerTester, fptrunc) {
@ -739,6 +739,48 @@ TEST_F(FpySequencerTester, fpext) {
ASSERT_EQ(res_f, expected);
}
TEST_F(FpySequencerTester, fptosi) {
F64 src = 123.123;
I64 expected = static_cast<I64>(src);
I64 isrc;
memcpy(&isrc, &src, sizeof(isrc));
I64 res = tester_unaryRegOp_fptosi(isrc);
ASSERT_EQ(res, expected);
}
TEST_F(FpySequencerTester, sitofp) {
I64 src = 123;
F64 expected = static_cast<F64>(src);
I64 res = tester_unaryRegOp_sitofp(src);
F64 fres;
memcpy(&fres, &res, sizeof(res));
ASSERT_EQ(fres, expected);
}
TEST_F(FpySequencerTester, fptoui) {
F64 src = 123.123;
U64 expected = static_cast<U64>(src);
I64 isrc;
memcpy(&isrc, &src, sizeof(isrc));
I64 res = tester_unaryRegOp_fptoui(isrc);
ASSERT_EQ(static_cast<U64>(res), expected);
}
TEST_F(FpySequencerTester, uitofp) {
U64 src = std::numeric_limits<U64>::max();
F64 expected = static_cast<F64>(src);
I64 res = tester_unaryRegOp_uitofp(static_cast<I64>(src));
F64 fres;
memcpy(&fres, &res, sizeof(res));
ASSERT_EQ(fres, expected);
}
TEST_F(FpySequencerTester, exit) {
FpySequencer_ExitDirective directive(true);
DirectiveError err = DirectiveError::NO_ERROR;
@ -1193,20 +1235,20 @@ TEST_F(FpySequencerTester, readBytes) {
tester_get_m_sequenceBuffer_ptr()->setExtBuffer(data, sizeof(data));
Os::File seqFile;
ASSERT_EQ(seqFile.open("test.bin", Os::File::OPEN_READ), Os::File::OP_OK);
ASSERT_EQ(tester_readBytes(seqFile, Fpy::Header::SERIALIZED_SIZE, true), Fw::Success::SUCCESS);
ASSERT_EQ(tester_readBytes(seqFile, Fpy::Header::SERIALIZED_SIZE, FpySequencer_FileReadStage::HEADER, true), Fw::Success::SUCCESS);
seqFile.close();
// check capacity too low
tester_get_m_sequenceBuffer_ptr()->setExtBuffer(data, Fpy::Header::SERIALIZED_SIZE - 1);
ASSERT_EQ(seqFile.open("test.bin", Os::File::OPEN_READ), Os::File::OP_OK);
ASSERT_EQ(tester_readBytes(seqFile, Fpy::Header::SERIALIZED_SIZE, true), Fw::Success::FAILURE);
ASSERT_EQ(tester_readBytes(seqFile, Fpy::Header::SERIALIZED_SIZE, FpySequencer_FileReadStage::HEADER, true), Fw::Success::FAILURE);
seqFile.close();
// check not enough bytes
tester_get_m_sequenceBuffer_ptr()->setExtBuffer(data,
Fpy::Header::SERIALIZED_SIZE + Fpy::Footer::SERIALIZED_SIZE + 1);
ASSERT_EQ(seqFile.open("test.bin", Os::File::OPEN_READ), Os::File::OP_OK);
ASSERT_EQ(tester_readBytes(seqFile, Fpy::Header::SERIALIZED_SIZE + Fpy::Footer::SERIALIZED_SIZE + 1, true),
ASSERT_EQ(tester_readBytes(seqFile, Fpy::Header::SERIALIZED_SIZE + Fpy::Footer::SERIALIZED_SIZE + 1, FpySequencer_FileReadStage::HEADER, true),
Fw::Success::FAILURE);
seqFile.close();
@ -1214,7 +1256,7 @@ TEST_F(FpySequencerTester, readBytes) {
// read after close
ASSERT_DEATH_IF_SUPPORTED(
tester_readBytes(seqFile, Fpy::Header::SERIALIZED_SIZE + Fpy::Footer::SERIALIZED_SIZE, true), "Assert: ");
tester_readBytes(seqFile, Fpy::Header::SERIALIZED_SIZE + Fpy::Footer::SERIALIZED_SIZE, FpySequencer_FileReadStage::HEADER, true), "Assert: ");
}
TEST_F(FpySequencerTester, validate) {

View File

@ -113,5 +113,21 @@ TEST_F(FpySequencerTester, CmpIntTlm) {
dispatchUntilState(State::IDLE);
ASSERT_EQ(tester_get_m_statementsDispatched(), 8);
}
TEST_F(FpySequencerTester, NotTrueSeq) {
// this sequence caught one bug
allocMem();
add_SET_REG(0, 255);
add_UNARY_REG_OP(0, 1, Fpy::DirectiveId::NOT);
add_IF(1, 4);
// should not get here
add_EXIT(false);
add_EXIT(true);
writeAndRun();
dispatchUntilState(State::IDLE);
// not of 255 should be interpreted as false
ASSERT_EQ(tester_get_m_tlm_ptr()->lastDirectiveError, DirectiveError::NO_ERROR);
}
}

View File

@ -421,8 +421,8 @@ Svc::FpySequencer::Telemetry* FpySequencerTester::tester_get_m_tlm_ptr() {
return &this->cmp.m_tlm;
}
Fw::Success FpySequencerTester::tester_readBytes(Os::File& file, FwSizeType readLen, bool updateCrc) {
return this->cmp.readBytes(file, readLen, updateCrc);
Fw::Success FpySequencerTester::tester_readBytes(Os::File& file, FwSizeType readLen, FpySequencer_FileReadStage readStage, bool updateCrc) {
return this->cmp.readBytes(file, readLen, readStage, updateCrc);
}
Fw::Success FpySequencerTester::tester_readFooter() {
@ -545,6 +545,18 @@ I64 FpySequencerTester::tester_unaryRegOp_fpext(I64 src) {
I64 FpySequencerTester::tester_unaryRegOp_fptrunc(I64 src) {
return this->cmp.unaryRegOp_fptrunc(src);
}
I64 FpySequencerTester::tester_unaryRegOp_fptosi(I64 src) {
return this->cmp.unaryRegOp_fptosi(src);
}
I64 FpySequencerTester::tester_unaryRegOp_sitofp(I64 src) {
return this->cmp.unaryRegOp_sitofp(src);
}
I64 FpySequencerTester::tester_unaryRegOp_fptoui(I64 src) {
return this->cmp.unaryRegOp_fptoui(src);
}
I64 FpySequencerTester::tester_unaryRegOp_uitofp(I64 src) {
return this->cmp.unaryRegOp_uitofp(src);
}
void FpySequencerTester::tester_doDispatch() {
this->cmp.doDispatch();
}

View File

@ -167,6 +167,10 @@ class FpySequencerTester : public FpySequencerGTestBase, public ::testing::Test
I64 tester_unaryRegOp_not(I64 src);
I64 tester_unaryRegOp_fpext(I64 src);
I64 tester_unaryRegOp_fptrunc(I64 src);
I64 tester_unaryRegOp_fptoui(I64 src);
I64 tester_unaryRegOp_uitofp(I64 src);
I64 tester_unaryRegOp_fptosi(I64 src);
I64 tester_unaryRegOp_sitofp(I64 src);
FpySequencer::Runtime* tester_get_m_runtime_ptr();
Fw::ExternalSerializeBuffer* tester_get_m_sequenceBuffer_ptr();
void tester_set_m_sequencesStarted(U64 val);
@ -179,7 +183,7 @@ class FpySequencerTester : public FpySequencerGTestBase, public ::testing::Test
Fw::Success tester_validate();
Fw::String tester_get_m_sequenceFilePath();
void tester_set_m_sequenceFilePath(Fw::String str);
Fw::Success tester_readBytes(Os::File& file, FwSizeType readLen, bool updateCrc = true);
Fw::Success tester_readBytes(Os::File& file, FwSizeType readLen, FpySequencer_FileReadStage readStage, bool updateCrc = true);
Fw::Success tester_readFooter();
Fw::Success tester_readBody();
Fw::Success tester_readHeader();

View File

@ -11,6 +11,6 @@ module Svc {
constant MAX_SERIALIZABLE_REGISTER_SIZE = 512 - 4 - 4
@ The number of registers available to a sequence
constant NUM_REGISTERS = 4
constant NUM_REGISTERS = 128
}
}