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

View File

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

View File

@ -23,8 +23,7 @@
static_assert(Svc::Fpy::MAX_SEQUENCE_ARG_COUNT <= std::numeric_limits<U8>::max(), static_assert(Svc::Fpy::MAX_SEQUENCE_ARG_COUNT <= std::numeric_limits<U8>::max(),
"Sequence arg count must be below U8 max"); "Sequence arg count must be below U8 max");
static_assert(Svc::Fpy::NUM_REGISTERS <= std::numeric_limits<U8>::max(), static_assert(Svc::Fpy::NUM_REGISTERS <= std::numeric_limits<U8>::max(), "Register count must be below U8 max");
"Register count must be below U8 max");
static_assert(Svc::Fpy::MAX_SEQUENCE_STATEMENT_COUNT <= std::numeric_limits<U16>::max(), static_assert(Svc::Fpy::MAX_SEQUENCE_STATEMENT_COUNT <= std::numeric_limits<U16>::max(),
"Sequence statement count must be below U16 max"); "Sequence statement count must be below U16 max");
static_assert(Svc::Fpy::MAX_SERIALIZABLE_REGISTER_SIZE <= std::numeric_limits<FwSizeType>::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; using DirectiveError = FpySequencer_DirectiveErrorCode;
class FpySequencer : public FpySequencerComponentBase { class FpySequencer : public FpySequencerComponentBase {
friend class FpySequencerTester;
friend class FpySequencerTester;
public: public:
union DirectiveUnion { union DirectiveUnion {
@ -78,17 +76,15 @@ class FpySequencer : public FpySequencerComponentBase {
//! //!
~FpySequencer(); ~FpySequencer();
private: private:
//! Handler for command RUN
//! Handler for command RUN //!
//! //! Loads, validates and runs a sequence
//! Loads, validates and runs a sequence void RUN_cmdHandler(FwOpcodeType opCode, //!< The opcode
void U32 cmdSeq, //!< The command sequence number
RUN_cmdHandler(FwOpcodeType opCode, //!< The opcode const Fw::CmdStringArg& fileName, //!< The name of the sequence file
U32 cmdSeq, //!< The command sequence number FpySequencer_BlockState block //!< Return command status when complete or not
const Fw::CmdStringArg& fileName, //!< The name of the sequence file ) override;
FpySequencer_BlockState block //!< Return command status when complete or not
) override;
//! Handler for command VALIDATE //! Handler for command VALIDATE
//! //!
@ -323,32 +319,30 @@ class FpySequencer : public FpySequencerComponentBase {
//! //!
//! called when a sequence failed to execute successfully //! called when a sequence failed to execute successfully
void Svc_FpySequencer_SequencerStateMachine_action_report_seqFailed( void Svc_FpySequencer_SequencerStateMachine_action_report_seqFailed(
SmId smId, //!< The state machine id SmId smId, //!< The state machine id
Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
) override; ) override;
//! Implementation for action report_seqStarted of state machine Svc_FpySequencer_SequencerStateMachine //! Implementation for action report_seqStarted of state machine Svc_FpySequencer_SequencerStateMachine
//! //!
//! reports that a sequence was started //! reports that a sequence was started
void Svc_FpySequencer_SequencerStateMachine_action_report_seqStarted( void Svc_FpySequencer_SequencerStateMachine_action_report_seqStarted(
SmId smId, //!< The state machine id SmId smId, //!< The state machine id
Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
) override; ) override;
protected: protected:
// ----------------------------------------------------------------------
// Functions to implement for internal state machine guards
// ----------------------------------------------------------------------
// ---------------------------------------------------------------------- //! Implementation for guard goalStateIs_RUNNING of state machine Svc_FpySequencer_SequencerStateMachine
// Functions to implement for internal state machine guards //!
// ---------------------------------------------------------------------- //! return true if the goal state is RUNNING
bool Svc_FpySequencer_SequencerStateMachine_guard_goalStateIs_RUNNING(
//! Implementation for guard goalStateIs_RUNNING of state machine Svc_FpySequencer_SequencerStateMachine SmId smId, //!< The state machine id
//! Svc_FpySequencer_SequencerStateMachine::Signal signal //!< The signal
//! return true if the goal state is RUNNING ) const override;
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 //! Implementation for guard shouldDebugBreak of state machine Svc_FpySequencer_SequencerStateMachine
//! //!
@ -384,9 +378,7 @@ class FpySequencer : public FpySequencerComponentBase {
) override; ) override;
//! Handler for input port seqRunIn //! Handler for input port seqRunIn
void seqRunIn_handler(FwIndexType portNum, void seqRunIn_handler(FwIndexType portNum, const Fw::StringBase& filename) override;
const Fw::StringBase& filename
) override;
//! Handler for input port pingIn //! Handler for input port pingIn
void pingIn_handler(FwIndexType portNum, //!< The port number 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; void directive_cmd_internalInterfaceHandler(const Svc::FpySequencer_CmdDirective& directive) override;
//! Internal interface handler for directive_deserSerReg //! 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 //! Internal interface handler for directive_setReg
void directive_setReg_internalInterfaceHandler(const Svc::FpySequencer_SetRegDirective& directive) override; void directive_setReg_internalInterfaceHandler(const Svc::FpySequencer_SetRegDirective& directive) override;
//! Internal interface handler for directive_binaryRegOp //! 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 //! Internal interface handler for directive_unaryRegOp
void directive_unaryRegOp_internalInterfaceHandler(const Svc::FpySequencer_UnaryRegOpDirective& directive) override; 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 allocateBuffer(FwEnumStoreType identifier, Fw::MemAllocator& allocator, FwSizeType bytes);
void deallocateBuffer(Fw::MemAllocator& allocator); void deallocateBuffer(Fw::MemAllocator& allocator);
private :
static constexpr U32 CRC_INITIAL_VALUE = 0xFFFFFFFFU; private:
static constexpr U32 CRC_INITIAL_VALUE = 0xFFFFFFFFU;
// allocated at startup // allocated at startup
Fw::ExternalSerializeBuffer m_sequenceBuffer; 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 // updates the CRC by default, but can be turned off if the contents
// aren't included in CRC. // aren't included in CRC.
// return success if successful // 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 // Run state
@ -648,6 +645,10 @@ class FpySequencer : public FpySequencerComponentBase {
I64 unaryRegOp_not(I64 src); I64 unaryRegOp_not(I64 src);
I64 unaryRegOp_fpext(I64 src); I64 unaryRegOp_fpext(I64 src);
I64 unaryRegOp_fptrunc(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); 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 //! 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; DirectiveError error = DirectiveError::NO_ERROR;
this->sendSignal(this->binaryRegOp_directiveHandler(directive, error)); this->sendSignal(this->binaryRegOp_directiveHandler(directive, error));
this->m_tlm.lastDirectiveError = error; this->m_tlm.lastDirectiveError = error;
} }
//! Internal interface handler for directive_unaryRegOp //! 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; DirectiveError error = DirectiveError::NO_ERROR;
this->sendSignal(this->unaryRegOp_directiveHandler(directive, error)); this->sendSignal(this->unaryRegOp_directiveHandler(directive, error));
this->m_tlm.lastDirectiveError = 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, Signal FpySequencer::binaryRegOp_directiveHandler(const FpySequencer_BinaryRegOpDirective& directive,
DirectiveError& error) { DirectiveError& error) {
// coding error, should not have gotten to this binary reg op handler // 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, FW_ASSERT(directive.get_op() >= Fpy::DirectiveId::OR && directive.get_op() <= Fpy::DirectiveId::FGE,
static_cast<FwAssertArgType>(directive.get_op())); static_cast<FwAssertArgType>(directive.get_op()));
@ -565,7 +566,10 @@ Signal FpySequencer::binaryRegOp_directiveHandler(const FpySequencer_BinaryRegOp
return Signal::stmtResponse_success; return Signal::stmtResponse_success;
} }
I64 FpySequencer::unaryRegOp_not(I64 src) { 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) { I64 FpySequencer::unaryRegOp_fpext(I64 src) {
// convert F32 to F64 // convert F32 to F64
@ -594,10 +598,41 @@ I64 FpySequencer::unaryRegOp_fptrunc(I64 src) {
// then extend to I64 // then extend to I64
return static_cast<I64>(itrunc); return static_cast<I64>(itrunc);
} }
I64 FpySequencer::unaryRegOp_fptosi(I64 src) {
Signal FpySequencer::unaryRegOp_directiveHandler(const FpySequencer_UnaryRegOpDirective& directive, DirectiveError& error) { // 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 // 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())); static_cast<FwAssertArgType>(directive.get_op()));
if (directive.getsrc() >= Fpy::NUM_REGISTERS || directive.getres() >= Fpy::NUM_REGISTERS) { 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 src = reg(directive.getsrc());
I64& res = reg(directive.getres()); I64& res = reg(directive.getres());
switch (directive.get_op()) { switch (directive.get_op()) {
case Fpy::DirectiveId::NOT: case Fpy::DirectiveId::NOT:
res = this->unaryRegOp_not(src); res = this->unaryRegOp_not(src);
@ -618,6 +653,18 @@ Signal FpySequencer::unaryRegOp_directiveHandler(const FpySequencer_UnaryRegOpDi
case Fpy::DirectiveId::FPTRUNC: case Fpy::DirectiveId::FPTRUNC:
res = this->unaryRegOp_fptrunc(src); res = this->unaryRegOp_fptrunc(src);
break; 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: default:
FW_ASSERT(0, directive.get_op()); FW_ASSERT(0, directive.get_op());
break; break;

View File

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

View File

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

View File

@ -49,11 +49,18 @@ module Svc {
# unary reg op dirs # unary reg op dirs
NOT = 33 NOT = 33
# floating point extension and truncation
FPEXT = 34 FPEXT = 34
FPTRUNC = 35 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 # end unary reg op dirs
EXIT = 36 EXIT = 40
} }
struct Header { struct Header {

View File

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

View File

@ -691,12 +691,12 @@ TEST_F(FpySequencerTester, setReg) {
TEST_F(FpySequencerTester, unaryRegOp) { TEST_F(FpySequencerTester, unaryRegOp) {
// Test NOT // Test NOT
FpySequencer_UnaryRegOpDirective directiveNOT(0, 1, Fpy::DirectiveId::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; DirectiveError err = DirectiveError::NO_ERROR;
Signal result = tester_unaryRegOp_directiveHandler(directiveNOT, err); Signal result = tester_unaryRegOp_directiveHandler(directiveNOT, err);
ASSERT_EQ(result, Signal::stmtResponse_success); ASSERT_EQ(result, Signal::stmtResponse_success);
ASSERT_EQ(err, DirectiveError::NO_ERROR); 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 // Test out-of-bounds register index
FpySequencer_UnaryRegOpDirective directiveOOB(Fpy::NUM_REGISTERS, 1, Fpy::DirectiveId::FPEXT); FpySequencer_UnaryRegOpDirective directiveOOB(Fpy::NUM_REGISTERS, 1, Fpy::DirectiveId::FPEXT);
@ -711,7 +711,7 @@ TEST_F(FpySequencerTester, unaryRegOp) {
TEST_F(FpySequencerTester, not) { TEST_F(FpySequencerTester, not) {
ASSERT_EQ(tester_unaryRegOp_not(0x123), ~0x123); ASSERT_EQ(tester_unaryRegOp_not(true), false);
} }
TEST_F(FpySequencerTester, fptrunc) { TEST_F(FpySequencerTester, fptrunc) {
@ -739,6 +739,48 @@ TEST_F(FpySequencerTester, fpext) {
ASSERT_EQ(res_f, expected); 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) { TEST_F(FpySequencerTester, exit) {
FpySequencer_ExitDirective directive(true); FpySequencer_ExitDirective directive(true);
DirectiveError err = DirectiveError::NO_ERROR; DirectiveError err = DirectiveError::NO_ERROR;
@ -1193,20 +1235,20 @@ TEST_F(FpySequencerTester, readBytes) {
tester_get_m_sequenceBuffer_ptr()->setExtBuffer(data, sizeof(data)); tester_get_m_sequenceBuffer_ptr()->setExtBuffer(data, sizeof(data));
Os::File seqFile; Os::File seqFile;
ASSERT_EQ(seqFile.open("test.bin", Os::File::OPEN_READ), Os::File::OP_OK); 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(); seqFile.close();
// check capacity too low // check capacity too low
tester_get_m_sequenceBuffer_ptr()->setExtBuffer(data, Fpy::Header::SERIALIZED_SIZE - 1); 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(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(); seqFile.close();
// check not enough bytes // check not enough bytes
tester_get_m_sequenceBuffer_ptr()->setExtBuffer(data, tester_get_m_sequenceBuffer_ptr()->setExtBuffer(data,
Fpy::Header::SERIALIZED_SIZE + Fpy::Footer::SERIALIZED_SIZE + 1); 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(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); Fw::Success::FAILURE);
seqFile.close(); seqFile.close();
@ -1214,7 +1256,7 @@ TEST_F(FpySequencerTester, readBytes) {
// read after close // read after close
ASSERT_DEATH_IF_SUPPORTED( 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) { TEST_F(FpySequencerTester, validate) {

View File

@ -113,5 +113,21 @@ TEST_F(FpySequencerTester, CmpIntTlm) {
dispatchUntilState(State::IDLE); dispatchUntilState(State::IDLE);
ASSERT_EQ(tester_get_m_statementsDispatched(), 8); 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; return &this->cmp.m_tlm;
} }
Fw::Success FpySequencerTester::tester_readBytes(Os::File& file, FwSizeType readLen, bool updateCrc) { Fw::Success FpySequencerTester::tester_readBytes(Os::File& file, FwSizeType readLen, FpySequencer_FileReadStage readStage, bool updateCrc) {
return this->cmp.readBytes(file, readLen, updateCrc); return this->cmp.readBytes(file, readLen, readStage, updateCrc);
} }
Fw::Success FpySequencerTester::tester_readFooter() { Fw::Success FpySequencerTester::tester_readFooter() {
@ -545,6 +545,18 @@ I64 FpySequencerTester::tester_unaryRegOp_fpext(I64 src) {
I64 FpySequencerTester::tester_unaryRegOp_fptrunc(I64 src) { I64 FpySequencerTester::tester_unaryRegOp_fptrunc(I64 src) {
return this->cmp.unaryRegOp_fptrunc(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() { void FpySequencerTester::tester_doDispatch() {
this->cmp.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_not(I64 src);
I64 tester_unaryRegOp_fpext(I64 src); I64 tester_unaryRegOp_fpext(I64 src);
I64 tester_unaryRegOp_fptrunc(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(); FpySequencer::Runtime* tester_get_m_runtime_ptr();
Fw::ExternalSerializeBuffer* tester_get_m_sequenceBuffer_ptr(); Fw::ExternalSerializeBuffer* tester_get_m_sequenceBuffer_ptr();
void tester_set_m_sequencesStarted(U64 val); void tester_set_m_sequencesStarted(U64 val);
@ -179,7 +183,7 @@ class FpySequencerTester : public FpySequencerGTestBase, public ::testing::Test
Fw::Success tester_validate(); Fw::Success tester_validate();
Fw::String tester_get_m_sequenceFilePath(); Fw::String tester_get_m_sequenceFilePath();
void tester_set_m_sequenceFilePath(Fw::String str); 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_readFooter();
Fw::Success tester_readBody(); Fw::Success tester_readBody();
Fw::Success tester_readHeader(); Fw::Success tester_readHeader();

View File

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