<commit_before>#include "writer/verilog/wire/mux_node.h"

#include "iroha/logging.h"
#include "writer/verilog/ports.h"
#include "writer/verilog/resource.h"
#include "writer/verilog/table.h"
#include "writer/verilog/wire/accessor_info.h"
#include "writer/verilog/wire/mux.h"
#include "writer/verilog/wire/wire_set.h"

// Up-stream <--> Down-stream
//
// Basic structure:
//   NodeWire <---Mux+--- c0.NodeWire()
//                   +--- c1.NodeWire()
//                        ..
//
// Staged:
//   wdata:
//     NodeWire = NodeWireWithReg
//     NodeWireWithReg <= aribiter(c0.NodeWire(), c1.NodeWire(), ...)
//   rdata, notify accessor:
//     NodeWireWithReg <= NodeWire
//     c0.NodeWire = NodeWireWithReg
//     c1.NodeWire = NodeWireWithReg
//     ...
//   notify parent:
//     NodeWire = NodeWireWithReg
//     NodeWireWithReg <= |c0.NodeWire(), c1.NodeWire, ...
//   req:
//     NodeWire = NodeWireWithReg
//     NodeWireWithReg <= |c0.NodeWire(), c1.NodeWire, ...
//   ack:
//     NodeWireWithReg <= NodeWire
//     c0.NodeWire = arbiter(NodeWireWithReg)
//     c1.NodeWire = arbiter(NodeWireWithReg)

namespace iroha {
namespace writer {
namespace verilog {
namespace wire {

MuxNode::MuxNode(const Mux *mux, int id, const AccessorInfo *accessor)
  : mux_(mux), id_(id), ws_(mux->GetWireSet()), accessor_(accessor) {
}

bool MuxNode::IsRoot() const {
  return (mux_->GetRootNode() == this);
}

bool MuxNode::IsLeaf() const {
  return (accessor_ != nullptr);
}

bool MuxNode::IsStaged() const {
  // WIP.
  return false; // !(IsRoot() || IsLeaf());
}

void MuxNode::WriteIOWire(Ports *ports, ostream &os) {
  for (MuxNode *cn : children_) {
    cn->WriteIOWire(ports, os);
  }
  // Root or leaf nodes have external wires.
  if (IsRoot()) {
    auto sigs = ws_->GetSignals();
    for (auto &sig : sigs) {
      string n = NodeWireName(*sig);
      int w = sig->width_;
      if (sig->IsUpstream()) {
	ports->AddPort(n, Port::OUTPUT_WIRE, w);
      } else {
	ports->AddPort(n, Port::INPUT, w);
      }
    }
  }
  if (IsLeaf()) {
    const auto &asigs = accessor_->GetSignals();
    for (auto &asig : asigs) {
      string s = NodeWireName(*(asig->sig_desc_));
      int w = asig->sig_desc_->width_;
      if (asig->sig_desc_->IsUpstream()) {
	ports->AddPort(s, Port::INPUT, w);
      } else {
	ports->AddPort(s, Port::OUTPUT_WIRE, w);
      }
    }
  }
}

void MuxNode::WriteMux(ostream &os) {
  if (IsLeaf()) {
    return;
  }
  os << "\n  // node:" << id_ << " " << children_.size() << " child nodes";
  if (IsStaged()) {
    os << " - staged";
  }
  os << "\n";
  auto sigs = ws_->GetSignals();
  SignalDescription *req_desc = nullptr;
  SignalDescription *ack_desc = nullptr;
  SignalDescription *notify_desc = nullptr;
  SignalDescription *notify_secondary_desc = nullptr;
  for (SignalDescription *desc : sigs) {
    if (desc->type_ == AccessorSignalType::ACCESSOR_REQ) {
      req_desc = desc;
    }
    if (desc->type_ == AccessorSignalType::ACCESSOR_ACK) {
      ack_desc = desc;
    }
    if (desc->type_ == AccessorSignalType::ACCESSOR_NOTIFY_PARENT) {
      notify_desc = desc;
    }
    if (desc->type_ == AccessorSignalType::ACCESSOR_NOTIFY_PARENT_SECONDARY) {
      notify_secondary_desc = desc;
    }
  }
  if (req_desc != nullptr && ack_desc != nullptr) {
    BuildArbitration(*req_desc, *ack_desc, os);
  }
  for (SignalDescription *desc : sigs) {
    switch (desc->type_) {
    case AccessorSignalType::ACCESSOR_WRITE_ARG:
      BuildWriteArg(*desc, req_desc, notify_desc, notify_secondary_desc, os);
      break;
    case AccessorSignalType::ACCESSOR_READ_ARG:
      BuildReadArg(*desc, os);
      break;
    case AccessorSignalType::ACCESSOR_NOTIFY_PARENT:
    case AccessorSignalType::ACCESSOR_NOTIFY_PARENT_SECONDARY:
      BuildNotifyParent(*desc, os);
      break;
    case AccessorSignalType::ACCESSOR_NOTIFY_ACCESSOR:
      BuildNotifyAccessor(*desc, os);
      break;
    default:
      break;
    }
  }
  if (IsStaged()) {
    WriteStage(os);
  }
  for (MuxNode *cn : children_) {
    cn->WriteMux(os);
  }
}

void MuxNode::WriteStage(ostream &os) {
  const Table &tab = ws_->GetResource().GetTable();
  os << "\n  // stage\n" << as_.str();
  tab.WriteAlwaysBlockHead(os);
  os << is_.str();
  tab.WriteAlwaysBlockMiddle(os);
  os << ss_.str();
  tab.WriteAlwaysBlockTail(os);
}

void MuxNode::WriteDecls(ostream &os) {
  if (IsLeaf()) {
    return;
  }
  for (MuxNode *cn : children_) {
    cn->WriteDecls(os);
  }
  if (IsRoot()) {
    return;
  }
  auto sigs = ws_->GetSignals();
  for (SignalDescription *desc : sigs) {
    os << "  wire " << Table::WidthSpec(desc->width_)
       << NodeWireName(*desc) << ";\n";
    if (IsStaged()) {
      os << "  reg " << Table::WidthSpec(desc->width_)
	 << NodeWireNameWithReg(*desc) << ";\n";
    }
  }
  if (IsStaged()) {
    os << "  reg [1:0] " << HandShakeState() << ";\n";
  }
}

void MuxNode::BuildWriteArg(const SignalDescription &arg_desc,
			    const SignalDescription *req_desc,
			    const SignalDescription *notify_desc,
			    const SignalDescription *notify_secondary_desc,
			    ostream &os) {
  // wire names of write_arg, req
  vector<pair<string, string> > pins;<commit_msg>Allow root node to be staged.<commit_after>#include "writer/verilog/wire/mux_node.h"

#include "iroha/logging.h"
#include "writer/verilog/ports.h"
#include "writer/verilog/resource.h"
#include "writer/verilog/table.h"
#include "writer/verilog/wire/accessor_info.h"
#include "writer/verilog/wire/mux.h"
#include "writer/verilog/wire/wire_set.h"

// Up-stream <--> Down-stream
//
// Basic structure:
//   NodeWire <---Mux+--- c0.NodeWire()
//                   +--- c1.NodeWire()
//                        ..
//
// Staged:
//   wdata:
//     NodeWire = NodeWireWithReg
//     NodeWireWithReg <= aribiter(c0.NodeWire(), c1.NodeWire(), ...)
//   rdata, notify accessor:
//     NodeWireWithReg <= NodeWire
//     c0.NodeWire = NodeWireWithReg
//     c1.NodeWire = NodeWireWithReg
//     ...
//   notify parent:
//     NodeWire = NodeWireWithReg
//     NodeWireWithReg <= |c0.NodeWire(), c1.NodeWire, ...
//   req:
//     NodeWire = NodeWireWithReg
//     NodeWireWithReg <= |c0.NodeWire(), c1.NodeWire, ...
//   ack:
//     NodeWireWithReg <= NodeWire
//     c0.NodeWire = arbiter(NodeWireWithReg)
//     c1.NodeWire = arbiter(NodeWireWithReg)

namespace iroha {
namespace writer {
namespace verilog {
namespace wire {

MuxNode::MuxNode(const Mux *mux, int id, const AccessorInfo *accessor)
  : mux_(mux), id_(id), ws_(mux->GetWireSet()), accessor_(accessor) {
}

bool MuxNode::IsRoot() const {
  return (mux_->GetRootNode() == this);
}

bool MuxNode::IsLeaf() const {
  return (accessor_ != nullptr);
}

bool MuxNode::IsStaged() const {
  // WIP.
  return false; // !(IsRoot() || IsLeaf());
}

void MuxNode::WriteIOWire(Ports *ports, ostream &os) {
  for (MuxNode *cn : children_) {
    cn->WriteIOWire(ports, os);
  }
  // Root or leaf nodes have external wires.
  if (IsRoot()) {
    auto sigs = ws_->GetSignals();
    for (auto &sig : sigs) {
      string n = NodeWireName(*sig);
      int w = sig->width_;
      if (sig->IsUpstream()) {
	ports->AddPort(n, Port::OUTPUT_WIRE, w);
      } else {
	ports->AddPort(n, Port::INPUT, w);
      }
    }
  }
  if (IsLeaf()) {
    const auto &asigs = accessor_->GetSignals();
    for (auto &asig : asigs) {
      string s = NodeWireName(*(asig->sig_desc_));
      int w = asig->sig_desc_->width_;
      if (asig->sig_desc_->IsUpstream()) {
	ports->AddPort(s, Port::INPUT, w);
      } else {
	ports->AddPort(s, Port::OUTPUT_WIRE, w);
      }
    }
  }
}

void MuxNode::WriteMux(ostream &os) {
  if (IsLeaf()) {
    return;
  }
  os << "\n  // node:" << id_ << " " << children_.size() << " child nodes";
  if (IsStaged()) {
    os << " - staged";
  }
  os << "\n";
  auto sigs = ws_->GetSignals();
  SignalDescription *req_desc = nullptr;
  SignalDescription *ack_desc = nullptr;
  SignalDescription *notify_desc = nullptr;
  SignalDescription *notify_secondary_desc = nullptr;
  for (SignalDescription *desc : sigs) {
    if (desc->type_ == AccessorSignalType::ACCESSOR_REQ) {
      req_desc = desc;
    }
    if (desc->type_ == AccessorSignalType::ACCESSOR_ACK) {
      ack_desc = desc;
    }
    if (desc->type_ == AccessorSignalType::ACCESSOR_NOTIFY_PARENT) {
      notify_desc = desc;
    }
    if (desc->type_ == AccessorSignalType::ACCESSOR_NOTIFY_PARENT_SECONDARY) {
      notify_secondary_desc = desc;
    }
  }
  if (req_desc != nullptr && ack_desc != nullptr) {
    BuildArbitration(*req_desc, *ack_desc, os);
  }
  for (SignalDescription *desc : sigs) {
    switch (desc->type_) {
    case AccessorSignalType::ACCESSOR_WRITE_ARG:
      BuildWriteArg(*desc, req_desc, notify_desc, notify_secondary_desc, os);
      break;
    case AccessorSignalType::ACCESSOR_READ_ARG:
      BuildReadArg(*desc, os);
      break;
    case AccessorSignalType::ACCESSOR_NOTIFY_PARENT:
    case AccessorSignalType::ACCESSOR_NOTIFY_PARENT_SECONDARY:
      BuildNotifyParent(*desc, os);
      break;
    case AccessorSignalType::ACCESSOR_NOTIFY_ACCESSOR:
      BuildNotifyAccessor(*desc, os);
      break;
    default:
      break;
    }
  }
  if (IsStaged()) {
    WriteStage(os);
  }
  for (MuxNode *cn : children_) {
    cn->WriteMux(os);
  }
}

void MuxNode::WriteStage(ostream &os) {
  const Table &tab = ws_->GetResource().GetTable();
  os << "\n  // stage\n" << as_.str();
  tab.WriteAlwaysBlockHead(os);
  os << is_.str();
  tab.WriteAlwaysBlockMiddle(os);
  os << ss_.str();
  tab.WriteAlwaysBlockTail(os);
}

void MuxNode::WriteDecls(ostream &os) {
  if (IsLeaf()) {
    return;
  }
  for (MuxNode *cn : children_) {
    cn->WriteDecls(os);
  }
  auto sigs = ws_->GetSignals();
  for (SignalDescription *desc : sigs) {
    if (!IsRoot()) {
      os << "  wire " << Table::WidthSpec(desc->width_)
	 << NodeWireName(*desc) << ";\n";
    }
    if (IsStaged()) {
      os << "  reg " << Table::WidthSpec(desc->width_)
	 << NodeWireNameWithReg(*desc) << ";\n";
    }
  }
  if (IsStaged()) {
    os << "  reg [1:0] " << HandShakeState() << ";\n";
  }
}

void MuxNode::BuildWriteArg(const SignalDescription &arg_desc,
			    const SignalDescription *req_desc,
			    const SignalDescription *notify_desc,
			    const SignalDescription *notify_secondary_desc,
			    ostream &os) {
  // wire names of write_arg, req
  vector<pair<string, string> > pins;
{'fraction_non_alphanumeric': 0.16283783783783784, 'fraction_numerical': 0.002702702702702703, 'mean_word_length': 3.045685279187817, 'pattern_counts': {'":': 0, '<': 109, '<?xml version=': 0, '>': 65, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5814676', 'n_tokens_mistral': 3863, 'n_tokens_neox': 3699, 'n_words': 713}