diff --git a/xls/contrib/xlscc/translate_block.cc b/xls/contrib/xlscc/translate_block.cc index be49da490a..aa5cbf8c93 100644 --- a/xls/contrib/xlscc/translate_block.cc +++ b/xls/contrib/xlscc/translate_block.cc @@ -973,13 +973,20 @@ absl::StatusOr Translator::GenerateSubFSM( outer_prepared.xls_func->return_value_count, body_loc); xls::BValue context_out = pb.TupleIndex(ret_io_value, /*idx=*/0, body_loc); + xls::BValue enter_condition = + pb.TupleIndex(ret_io_value, /*idx=*/1, body_loc); + XLS_CHECK_EQ(enter_condition.GetType()->GetFlatBitCount(), 1); // Generate inner FSM XLS_ASSIGN_OR_RETURN( PipelinedLoopContentsReturn contents_ret, GenerateIR_PipelinedLoopContents( *sub_proc_invoked, pb, outer_prepared.token, context_out, - /*in_state_condition=*/outer_state.in_this_state, + /*in_state_condition=*/ + pb.And(outer_state.in_this_state, enter_condition, body_loc, + /*name=*/ + absl::StrFormat("%s_loop_contents_condition", + sub_proc_invoked->name_prefix)), /*in_fsm=*/true)); outer_prepared.token = contents_ret.token_out; @@ -1001,8 +1008,17 @@ absl::StatusOr Translator::GenerateSubFSM( absl::StrFormat("%s_state_%i_context_receive_invoke", fsm_prefix, outer_state.index)); + xls::BValue not_enter_condition = pb.Not( + enter_condition, body_loc, + /*name=*/ + absl::StrFormat("%s_not_enter_condition", sub_proc_invoked->name_prefix)); + return SubFSMReturn{ - .exit_state_condition = contents_ret.do_break, + .exit_state_condition = + pb.Or(not_enter_condition, contents_ret.do_break, body_loc, + /*name=*/ + absl::StrFormat("%s_not_exit_state_condition", + sub_proc_invoked->name_prefix)), .return_value = context_receive_ret_val, .extra_next_state_values = contents_ret.extra_next_state_values}; } diff --git a/xls/contrib/xlscc/unit_tests/translator_proc_test.cc b/xls/contrib/xlscc/unit_tests/translator_proc_test.cc index f59fc13d99..24ae03d180 100644 --- a/xls/contrib/xlscc/unit_tests/translator_proc_test.cc +++ b/xls/contrib/xlscc/unit_tests/translator_proc_test.cc @@ -6678,6 +6678,131 @@ TEST_P(TranslatorProcTest, PipelinedLoopSerialDataDependency) { } } +TEST_P(TranslatorProcTest, PipelinedLoopConditionFalse) { + const std::string content = R"( + class Block { + public: + __xls_channel& in; + __xls_channel& out; + + #pragma hls_top + void Run() { + int value = in.read(); + + #pragma hls_pipeline_init_interval 1 + for(int i=0;i<0;++i) { + out.write(55); + } + + #pragma hls_pipeline_init_interval 1 + for(int i=0;i<6;++i) { + out.write(value++); + } + } + };)"; + + absl::flat_hash_map> inputs; + inputs["in"] = {xls::Value(xls::SBits(11, 32))}; + + { + absl::flat_hash_map> outputs; + outputs["out"] = { + xls::Value(xls::SBits(11 + 0, 32)), xls::Value(xls::SBits(11 + 1, 32)), + xls::Value(xls::SBits(11 + 2, 32)), xls::Value(xls::SBits(11 + 3, 32)), + xls::Value(xls::SBits(11 + 4, 32)), xls::Value(xls::SBits(11 + 5, 32))}; + ProcTest(content, /*block_spec=*/std::nullopt, inputs, outputs, + /* min_ticks = */ 1, + /* max_ticks = */ 100, + /* top_level_init_interval = */ 1); + } +} + +TEST_P(TranslatorProcTest, PipelinedLoopConditional) { + const std::string content = R"( + class Block { + public: + __xls_channel& in; + __xls_channel& out; + + #pragma hls_top + void Run() { + int value = in.read(); + + if(0) { + #pragma hls_pipeline_init_interval 1 + for(int i=0;i<0;++i) { + out.write(55); + } + } + + if(1) { + #pragma hls_pipeline_init_interval 1 + for(int i=0;i<6;++i) { + out.write(value++); + } + } + } + };)"; + + absl::flat_hash_map> inputs; + inputs["in"] = {xls::Value(xls::SBits(11, 32))}; + + { + absl::flat_hash_map> outputs; + outputs["out"] = { + xls::Value(xls::SBits(11 + 0, 32)), xls::Value(xls::SBits(11 + 1, 32)), + xls::Value(xls::SBits(11 + 2, 32)), xls::Value(xls::SBits(11 + 3, 32)), + xls::Value(xls::SBits(11 + 4, 32)), xls::Value(xls::SBits(11 + 5, 32))}; + ProcTest(content, /*block_spec=*/std::nullopt, inputs, outputs, + /* min_ticks = */ 1, + /* max_ticks = */ 100, + /* top_level_init_interval = */ 1); + } +} + +TEST_P(TranslatorProcTest, PipelinedLoopConditional2) { + const std::string content = R"( + class Block { + public: + __xls_channel& in; + __xls_channel& out; + + #pragma hls_top + void Run() { + int value = in.read(); + + if(0) { + #pragma hls_pipeline_init_interval 1 + for(int i=0;i<1;++i) { + ++value; + } + } + + if(1) { + #pragma hls_pipeline_init_interval 1 + for(int i=0;i<6;++i) { + out.write(value++); + } + } + } + };)"; + + absl::flat_hash_map> inputs; + inputs["in"] = {xls::Value(xls::SBits(11, 32))}; + + { + absl::flat_hash_map> outputs; + outputs["out"] = { + xls::Value(xls::SBits(11 + 0, 32)), xls::Value(xls::SBits(11 + 1, 32)), + xls::Value(xls::SBits(11 + 2, 32)), xls::Value(xls::SBits(11 + 3, 32)), + xls::Value(xls::SBits(11 + 4, 32)), xls::Value(xls::SBits(11 + 5, 32))}; + ProcTest(content, /*block_spec=*/std::nullopt, inputs, outputs, + /* min_ticks = */ 1, + /* max_ticks = */ 100, + /* top_level_init_interval = */ 1); + } +} + TEST_P(TranslatorProcTest, PipelinedLoopSerialAfterASAP) { const std::string content = R"( class Block {