src/CodeGen_CoreHLS.cpp
// Maybe first change toward a inner loop handling should be to run instruction collection on outer loops
// and thus save an activeloop list. Then generate a loopnestinfo data structure directly from that so that
// lp is not passed around as a parameter?
Maybe first change toward a inner loop handling should be to run instruction collection on outer loops
and thus save an activeloop list.
Maybe first change toward a inner loop handling should be to run instruction collection on outer loops and thus save an activeloop list .
KernelControlPath controlPathForKernel(HWFunction& f) {
  LoopNestInfo loopInfo;
  if (f.allInstrs().size() > 0) {
    HWInstr* fst = f.structuredOrder()[0];
    cout << "Adding surrounding loops from: " << *fst << endl;
    for (auto lp : fst->surroundingLoops) {
      loopInfo.loops.push_back({lp.name, func_id_const_value(lp.min), func_id_const_value(lp.extent)});
    }
  } else {
    cout << "Error: HWFunction..." << endl;
    cout << f << endl;
    cout << "has no instructions!" << endl;
    internal_assert(false);
  }
  cout << "# of levels in loop for control path = " << loopInfo.loops.size() << endl;
  auto c = f.mod->getContext();
  KernelControlPath cp;
  std::set<std::string> streamNames = allStreamNames(f);
  auto globalNs = c->getNamespace("global");
  vector<std::pair<std::string, CoreIR::Type*> > tps{{"reset", c->BitIn()}, {"in_en", c->BitIn()}};
  std::set<string> vars;
  for (auto instr : f.allInstrs()) {
    for (auto lp : instr->surroundingLoops) {
      vars.insert(lp.name);
    }
  }
  for (auto var : vars) {
    int width = 16;
    cp.controlVars.push_back(coreirSanitize(var));
    tps.push_back({coreirSanitize(var), c->Bit()->Arr(width)});
  }
  CoreIR::Module* controlPath = globalNs->newModuleDecl(f.name + "_control_path", c->Record(tps));
  auto def = controlPath->newModuleDef();
  int width = 16;
  std::vector<CoreIR::Wireable*> loopLevelCounters;
  std::vector<CoreIR::Wireable*> levelAtMax;
  std::set<std::string> loopVarNames;
  auto self = def->sel("self");
  for (auto l : loopInfo.loops) {
    int min_value = l.min;
    int max_value = min_value + l.extent - 1;
    int inc_value = 1;
    CoreIR::Values args = {{"width",CoreIR::Const::make(c, width)},
      {"min",CoreIR::Const::make(c, min_value)},
      {"max",CoreIR::Const::make(c, max_value)},
      {"inc",CoreIR::Const::make(c, inc_value)}};
    loopVarNames.insert(l.name);
    string varName = coreirSanitize(l.name);
    CoreIR::Wireable* counter_inst = def->addInstance(varName, "commonlib.counter", args);
    loopLevelCounters.push_back(counter_inst);
    if (self->canSel(varName)) {
      def->connect(counter_inst->sel("out"), self->sel(varName));
    }
    def->connect(counter_inst->sel("reset"), def->sel("self")->sel("reset"));
    auto maxValConst = mkConst(def, varName + "_max_value", width, max_value);
    auto atMax = def->addInstance(varName + "_at_max", "coreir.eq", {{"width", COREMK(c, width)}});
    def->connect(atMax->sel("in0"), maxValConst->sel("out"));
    def->connect(atMax->sel("in1"), counter_inst->sel("out"));
    levelAtMax.push_back(atMax);
  }
  internal_assert(levelAtMax.size() == loopLevelCounters.size());
  cout << "Wiring up counter enables for " << loopLevelCounters.size() << " loop levels" << endl;
  if (loopLevelCounters.size() > 0) {
    for (int i = 0; i < ((int) loopLevelCounters.size()) - 1; i++) {
      vector<CoreIR::Wireable*> below;
      for (int j = i + 1; j < (int) loopLevelCounters.size(); j++) {
        below.push_back(levelAtMax[j]->sel("out"));
      }
      CoreIR::Wireable* shouldInc = andList(def, below);
      def->connect(loopLevelCounters[i]->sel("en"), shouldInc);
    }
    def->connect(loopLevelCounters.back()->sel("en"), self->sel("in_en"));
  }
  controlPath->setDef(def);
  cp.m = controlPath;
  return cp;
}
KernelControlPath controlPathForKernel ( HWFunction & f ) { LoopNestInfo loopInfo ; if ( f . allInstrs ( ) . size ( ) > 0 ) { HWInstr * fst = f . structuredOrder ( ) [ 0 ] ; cout << " " << * fst << endl ; for ( auto lp : fst -> surroundingLoops ) { loopInfo . loops . push_back ( { lp . name , func_id_const_value ( lp . min ) , func_id_const_value ( lp . extent ) } ) ; } } else { cout << " " << endl ; cout << f << endl ; cout << " " << endl ; internal_assert ( false ) ; } cout << " " << loopInfo . loops . size ( ) << endl ; auto c = f . mod -> getContext ( ) ; KernelControlPath cp ; std :: set < std :: string > streamNames = allStreamNames ( f ) ; auto globalNs = c -> getNamespace ( " " ) ; vector < std :: pair < std :: string , CoreIR :: Type * > > tps { { " " , c -> BitIn ( ) } , { " " , c -> BitIn ( ) } } ; std :: set < string > vars ; for ( auto instr : f . allInstrs ( ) ) { for ( auto lp : instr -> surroundingLoops ) { vars . insert ( lp . name ) ; } } for ( auto var : vars ) { int width = 16 ; cp . controlVars . push_back ( coreirSanitize ( var ) ) ; tps . push_back ( { coreirSanitize ( var ) , c -> Bit ( ) -> Arr ( width ) } ) ; } CoreIR :: Module * controlPath = globalNs -> newModuleDecl ( f . name + " " , c -> Record ( tps ) ) ; auto def = controlPath -> newModuleDef ( ) ; int width = 16 ; std :: vector < CoreIR :: Wireable * > loopLevelCounters ; std :: vector < CoreIR :: Wireable * > levelAtMax ; std :: set < std :: string > loopVarNames ; auto self = def -> sel ( " " ) ; for ( auto l : loopInfo . loops ) { int min_value = l . min ; int max_value = min_value + l . extent - 1 ; int inc_value = 1 ; CoreIR :: Values args = { { " " , CoreIR :: Const :: make ( c , width ) } , { " " , CoreIR :: Const :: make ( c , min_value ) } , { " " , CoreIR :: Const :: make ( c , max_value ) } , { " " , CoreIR :: Const :: make ( c , inc_value ) } } ; loopVarNames . insert ( l . name ) ; string varName = coreirSanitize ( l . name ) ; CoreIR :: Wireable * counter_inst = def -> addInstance ( varName , " " , args ) ; loopLevelCounters . push_back ( counter_inst ) ; if ( self -> canSel ( varName ) ) { def -> connect ( counter_inst -> sel ( " " ) , self -> sel ( varName ) ) ; } def -> connect ( counter_inst -> sel ( " " ) , def -> sel ( " " ) -> sel ( " " ) ) ; auto maxValConst = mkConst ( def , varName + " " , width , max_value ) ; auto atMax = def -> addInstance ( varName + " " , " " , { { " " , COREMK ( c , width ) } } ) ; def -> connect ( atMax -> sel ( " " ) , maxValConst -> sel ( " " ) ) ; def -> connect ( atMax -> sel ( " " ) , counter_inst -> sel ( " " ) ) ; levelAtMax . push_back ( atMax ) ; } internal_assert ( levelAtMax . size ( ) == loopLevelCounters . size ( ) ) ; cout << " " << loopLevelCounters . size ( ) << " " << endl ; if ( loopLevelCounters . size ( ) > 0 ) { for ( int i = 0 ; i < ( ( int ) loopLevelCounters . size ( ) ) - 1 ; i ++ ) { vector < CoreIR :: Wireable * > below ; for ( int j = i + 1 ; j < ( int ) loopLevelCounters . size ( ) ; j ++ ) { below . push_back ( levelAtMax [ j ] -> sel ( " " ) ) ; } CoreIR :: Wireable * shouldInc = andList ( def , below ) ; def -> connect ( loopLevelCounters [ i ] -> sel ( " " ) , shouldInc ) ; } def -> connect ( loopLevelCounters . back ( ) -> sel ( " " ) , self -> sel ( " " ) ) ; } controlPath -> setDef ( def ) ; cp . m = controlPath ; return cp ; }
Maybe first change toward a inner loop handling should be to run instruction collection on outer loops
and thus save an activeloop list.
Maybe first change toward a inner loop handling should be to run instruction collection on outer loops and thus save an activeloop list .
// TODO: Do real traversal of instructions // If this loop variable is actually used in the kernel then connect it to the outside world