Skip to content

Commit 30773ab

Browse files
allightcopybara-github
authored andcommitted
Allow configuration of i/o flop on per-channel basis in IR
This adds support for input_flop_kind and output_flop_kind on channels. If present these override the codegen `--flop_inputs[_kind=...]` and `--flop_outputs[_kind=...]` flags for ports associated with those channels. These should be generated by the frontend or added by some other pass. These options have no effect on the semantics of the proc ir and are only a directive for codegen conversion. PiperOrigin-RevId: 706887241
1 parent b9afda7 commit 30773ab

27 files changed

+996
-256
lines changed

xls/codegen/BUILD

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,7 @@ cc_library(
507507
":ram_configuration",
508508
"//xls/common:proto_adaptor_utils",
509509
"//xls/ir:bits",
510+
"//xls/ir:channel",
510511
"//xls/ir:op",
511512
"//xls/ir:register",
512513
"//xls/ir:value",
@@ -943,6 +944,7 @@ cc_test(
943944
deps = [
944945
":module_signature",
945946
":module_signature_cc_proto",
947+
"//xls/common:proto_test_utils",
946948
"//xls/common:xls_gunit_main",
947949
"//xls/common/status:matchers",
948950
"//xls/ir",
@@ -1009,6 +1011,7 @@ cc_test(
10091011
":block_conversion",
10101012
":codegen_options",
10111013
":codegen_pass",
1014+
"//xls/common:casts",
10121015
"//xls/common:xls_gunit_main",
10131016
"//xls/common/logging:log_lines",
10141017
"//xls/common/status:matchers",
@@ -1022,6 +1025,7 @@ cc_test(
10221025
"//xls/ir:channel",
10231026
"//xls/ir:channel_cc_proto",
10241027
"//xls/ir:channel_ops",
1028+
"//xls/ir:clone_package",
10251029
"//xls/ir:function_builder",
10261030
"//xls/ir:ir_matcher",
10271031
"//xls/ir:ir_parser",

xls/codegen/block_conversion.cc

Lines changed: 69 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -823,8 +823,6 @@ absl::StatusOr<std::string> StreamingIOName(Node* node) {
823823
}
824824
}
825825

826-
827-
828826
// For each output streaming channel add a corresponding ready port (input
829827
// port). Combinationally combine those ready signals with their predicates to
830828
// generate an all_active_outputs_ready signal.
@@ -1366,41 +1364,42 @@ static absl::StatusOr<RegisterRead*> AddRegisterToRDVNodes(
13661364
}
13671365

13681366
// Adds a register after the input streaming channel's data and valid.
1369-
static absl::StatusOr<Node*> AddRegisterAfterStreamingInput(
1370-
StreamingInput& input, const CodegenOptions& options, Block* block,
1367+
static absl::Status AddRegisterAfterStreamingInput(
1368+
StreamingInput& input, FlopKind flop,
1369+
const std::optional<xls::Reset>& reset_behavior, Block* block,
13711370
std::vector<std::optional<Node*>>& valid_nodes) {
1372-
const std::optional<xls::Reset> reset_behavior = options.ResetBehavior();
1373-
13741371
XLS_ASSIGN_OR_RETURN(std::string port_name, StreamingIOName(*input.port));
1375-
if (options.flop_inputs_kind() ==
1376-
CodegenOptions::IOKind::kZeroLatencyBuffer) {
1377-
return AddZeroLatencyBufferToRDVNodes(*input.port, input.port_valid,
1378-
input.port_ready, port_name,
1379-
reset_behavior, block, valid_nodes);
1380-
}
1381-
1382-
if (options.flop_inputs_kind() == CodegenOptions::IOKind::kSkidBuffer) {
1383-
return AddSkidBufferToRDVNodes(*input.port, input.port_valid,
1372+
switch (flop) {
1373+
case FlopKind::kZeroLatency:
1374+
return AddZeroLatencyBufferToRDVNodes(*input.port, input.port_valid,
1375+
input.port_ready, port_name,
1376+
reset_behavior, block, valid_nodes)
1377+
.status();
1378+
case FlopKind::kSkid:
1379+
return AddSkidBufferToRDVNodes(*input.port, input.port_valid,
1380+
input.port_ready, port_name,
1381+
reset_behavior, block, valid_nodes)
1382+
.status();
1383+
case FlopKind::kFlop:
1384+
return AddRegisterToRDVNodes(*input.port, input.port_valid,
13841385
input.port_ready, port_name, reset_behavior,
1385-
block, valid_nodes);
1386-
}
1387-
1388-
if (options.flop_inputs_kind() == CodegenOptions::IOKind::kFlop) {
1389-
return AddRegisterToRDVNodes(*input.port, input.port_valid,
1390-
input.port_ready, port_name, reset_behavior,
1391-
block, valid_nodes);
1386+
block, valid_nodes)
1387+
.status();
1388+
case FlopKind::kNone:
1389+
return absl::OkStatus();
13921390
}
1393-
1394-
return absl::UnimplementedError(absl::StrFormat(
1395-
"Block conversion does not support registering input with kind %d",
1396-
options.flop_inputs_kind()));
13971391
}
13981392

13991393
// Adds a register after the input streaming channel's data and valid.
14001394
// Returns the node for the register_read of the data.
1401-
static absl::StatusOr<Node*> AddRegisterBeforeStreamingOutput(
1402-
StreamingOutput& output, const CodegenOptions& options, Block* block,
1395+
static absl::Status AddRegisterBeforeStreamingOutput(
1396+
StreamingOutput& output, FlopKind flop,
1397+
const std::optional<xls::Reset>& reset_behavior, Block* block,
14031398
std::vector<std::optional<Node*>>& valid_nodes) {
1399+
if (flop == FlopKind::kNone) {
1400+
// Non-flopped outputs need no additional buffers/logic
1401+
return absl::OkStatus();
1402+
}
14041403
// Add buffers before the data/valid output ports and after
14051404
// the ready input port to serve as points where the
14061405
// additional logic from AddRegisterToRDVNodes() can be inserted.
@@ -1435,30 +1434,28 @@ static absl::StatusOr<Node*> AddRegisterBeforeStreamingOutput(
14351434
XLS_RETURN_IF_ERROR(
14361435
output.port_ready->ReplaceUsesWith(output_port_ready_buf));
14371436

1438-
const std::optional<xls::Reset> reset_behavior = options.ResetBehavior();
1439-
1440-
if (options.flop_outputs_kind() ==
1441-
CodegenOptions::IOKind::kZeroLatencyBuffer) {
1442-
return AddZeroLatencyBufferToRDVNodes(
1443-
output_port_data_buf, output_port_valid_buf, output_port_ready_buf,
1444-
port_name, reset_behavior, block, valid_nodes);
1445-
}
1446-
1447-
if (options.flop_outputs_kind() == CodegenOptions::IOKind::kSkidBuffer) {
1448-
return AddSkidBufferToRDVNodes(output_port_data_buf, output_port_valid_buf,
1437+
switch (flop) {
1438+
case FlopKind::kZeroLatency:
1439+
return AddZeroLatencyBufferToRDVNodes(output_port_data_buf,
1440+
output_port_valid_buf,
1441+
output_port_ready_buf, port_name,
1442+
reset_behavior, block, valid_nodes)
1443+
.status();
1444+
case FlopKind::kSkid:
1445+
return AddSkidBufferToRDVNodes(output_port_data_buf,
1446+
output_port_valid_buf,
1447+
output_port_ready_buf, port_name,
1448+
reset_behavior, block, valid_nodes)
1449+
.status();
1450+
case FlopKind::kFlop:
1451+
return AddRegisterToRDVNodes(output_port_data_buf, output_port_valid_buf,
14491452
output_port_ready_buf, port_name,
1450-
reset_behavior, block, valid_nodes);
1453+
reset_behavior, block, valid_nodes)
1454+
.status();
1455+
case FlopKind::kNone:
1456+
LOG(FATAL)
1457+
<< "Unreachable condition. Non-flopped should have short circuited.";
14511458
}
1452-
1453-
if (options.flop_outputs_kind() == CodegenOptions::IOKind::kFlop) {
1454-
return AddRegisterToRDVNodes(output_port_data_buf, output_port_valid_buf,
1455-
output_port_ready_buf, port_name,
1456-
reset_behavior, block, valid_nodes);
1457-
}
1458-
1459-
return absl::UnimplementedError(absl::StrFormat(
1460-
"Block conversion does not support registering output with kind %d",
1461-
options.flop_outputs_kind()));
14621459
}
14631460

14641461
// Adds an input and/or output flop and related signals.
@@ -1476,10 +1473,14 @@ static absl::Status AddInputOutputFlops(
14761473
// Flop streaming inputs.
14771474
for (auto& vec : streaming_io.inputs) {
14781475
for (StreamingInput& input : vec) {
1479-
if (options.flop_inputs()) {
1480-
XLS_RETURN_IF_ERROR(
1481-
AddRegisterAfterStreamingInput(input, options, block, valid_nodes)
1482-
.status());
1476+
StreamingChannel* channel = down_cast<StreamingChannel*>(input.channel);
1477+
FlopKind kind = channel->channel_config().input_flop_kind().value_or(
1478+
options.flop_inputs()
1479+
? CodegenOptions::IOKindToFlopKind(options.flop_inputs_kind())
1480+
: FlopKind::kNone);
1481+
if (kind != FlopKind::kNone) {
1482+
XLS_RETURN_IF_ERROR(AddRegisterAfterStreamingInput(
1483+
input, kind, options.ResetBehavior(), block, valid_nodes));
14831484

14841485
handled_io_nodes.insert(*input.port);
14851486
handled_io_nodes.insert(input.port_valid);
@@ -1494,10 +1495,14 @@ static absl::Status AddInputOutputFlops(
14941495
// Flop streaming outputs.
14951496
for (auto& vec : streaming_io.outputs) {
14961497
for (StreamingOutput& output : vec) {
1497-
if (options.flop_outputs()) {
1498-
XLS_RETURN_IF_ERROR(AddRegisterBeforeStreamingOutput(output, options,
1499-
block, valid_nodes)
1500-
.status());
1498+
StreamingChannel* channel = down_cast<StreamingChannel*>(output.channel);
1499+
FlopKind kind = channel->channel_config().output_flop_kind().value_or(
1500+
options.flop_outputs()
1501+
? CodegenOptions::IOKindToFlopKind(options.flop_outputs_kind())
1502+
: FlopKind::kNone);
1503+
if (kind != FlopKind::kNone) {
1504+
XLS_RETURN_IF_ERROR(AddRegisterBeforeStreamingOutput(
1505+
output, kind, options.ResetBehavior(), block, valid_nodes));
15011506

15021507
handled_io_nodes.insert(*output.port);
15031508
handled_io_nodes.insert(output.port_valid);
@@ -1884,7 +1889,6 @@ static absl::Status AddBubbleFlowControl(
18841889
return absl::OkStatus();
18851890
}
18861891

1887-
18881892
// Send/receive nodes are not cloned from the proc into the block, but the
18891893
// network of tokens connecting these send/receive nodes *is* cloned. This
18901894
// function removes the token operations.
@@ -2088,7 +2092,8 @@ class CloneNodesIntoBlockHandler {
20882092
channel->kind() == ChannelKind::kStreaming) {
20892093
StreamingChannel* streaming_channel =
20902094
down_cast<StreamingChannel*>(channel);
2091-
XLS_RET_CHECK(streaming_channel->fifo_config().has_value())
2095+
XLS_RET_CHECK(
2096+
streaming_channel->channel_config().fifo_config().has_value())
20922097
<< absl::StreamFormat("Channel %s has no fifo config.",
20932098
channel->name());
20942099

@@ -2102,7 +2107,8 @@ class CloneNodesIntoBlockHandler {
21022107
block()->AddInstantiation(
21032108
inst_name,
21042109
std::make_unique<xls::FifoInstantiation>(
2105-
inst_name, *streaming_channel->fifo_config(),
2110+
inst_name,
2111+
*streaming_channel->channel_config().fifo_config(),
21062112
streaming_channel->type(), streaming_channel->name(),
21072113
block()->package())));
21082114
itr->second = instantiation;
@@ -3092,10 +3098,8 @@ absl::Status SingleProcToPipelinedBlock(const PipelineSchedule& schedule,
30923098
VLOG(3) << absl::StrFormat("After Output Triggers");
30933099
XLS_VLOG_LINES(3, block->DumpIr());
30943100

3095-
if (options.flop_inputs() || options.flop_outputs()) {
3096-
XLS_RETURN_IF_ERROR(AddInputOutputFlops(options, streaming_io_and_pipeline,
3097-
block, proc_metadata.valid_flops));
3098-
}
3101+
XLS_RETURN_IF_ERROR(AddInputOutputFlops(options, streaming_io_and_pipeline,
3102+
block, proc_metadata.valid_flops));
30993103
VLOG(3) << "After Input or Output Flops";
31003104
XLS_VLOG_LINES(3, block->DumpIr());
31013105

0 commit comments

Comments
 (0)