/*
*===============================================================================
*
* d/wilson_d520/bgp_wilson.h
*
*-------------------------------------------------------------------------------
*
* Copyright (C) 2010 Thomas Streuer 
*
* This file is part of BQCD -- Berlin Quantum ChromoDynamics program
*
* BQCD is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* BQCD is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with BQCD.  If not, see <http:*www.gnu.org/licenses/>.
*
*-------------------------------------------------------------------------------
*/
#ifndef BGP_WILSON_H

#define BGP_WILSON_H

#include "asm_code.h"
#include "bgp_asm_code.h"

#include <vector>

class bgp_wilson_t :public asm_code_t
{
public:
  bgp_wilson_t(bool dagger, bool single, bool debug=false);
private:
  register_file_t gpr;
  register_file_t fpr;
  register_file_t cr;
  asm_stack_t stack;
  asm_label_t label;
  void header();
  void alloc_regs();
  void init_regs();
  void init_stack();
  void finish();
  void upd_load_reg_psi(unsigned fw, unsigned mu, int a);
  void load_psi(unsigned fw, unsigned mu, unsigned i);
  void pref_psi(unsigned i);
  void pref_r(unsigned i);
  void load_U(unsigned fw, unsigned mu, unsigned i);
  void mult(unsigned fw, unsigned mu, unsigned i);
  void add_to_res(unsigned fw, unsigned mu, unsigned i);
  void psi_pr(unsigned fw, unsigned mu, unsigned i);
  unsigned store_res_offs_reg(unsigned i);
  void store_res(unsigned i);
  void upd_shadow_ctr(unsigned ctr, unsigned i);
  void upd_hw_counters(unsigned fw, unsigned mu, unsigned i);
  void cmp_counters(unsigned i);
  void prolog();
  void epilog();
  void wait_counters();
  unsigned fpr_U_idx(unsigned fw, unsigned mu, unsigned i);
  unsigned fpr_psi_idx(unsigned fw, unsigned mu, unsigned col, unsigned hsp, unsigned pass);
  void mult_Upsi(unsigned fw, unsigned mu);
  void debug_regs();
  static const unsigned gpr_0;
  static const unsigned gpr_16;       // constant "16"
  static const unsigned gpr_sp;       // stack pointer (gpr 1)
  static const unsigned gpr_psi_base; // pointer to spinor (gpr 4, input)
  static const unsigned gpr_store_r;  // pointer to output spinor(gpr 5, input)
  static const unsigned gpr_data;     // pointer to data (gpr 6, input)
  static const unsigned cr_0;
  bool dagger_;
  bool single_;
  bool debug_;
  unsigned gpr_load_U;                // pointer to gauge field (gpr 3, input)
  unsigned gpr_nb;                    // neighbor array
  unsigned gpr_nb_idx;
  unsigned gpr_m16;                   // constant "-16"
  unsigned gpr_32;                    // constant "32"
  unsigned gpr_48;                    // constant "48"
  unsigned gpr_64;                    // constant "64"
  unsigned gpr_80;                    // constant "80"
  unsigned gpr_m80;                   // constant "-80"
  unsigned gpr_96;                    // constant "96"
  unsigned gpr_m96;                   // constant "-96"
  unsigned gpr_pref_psi;              // spinor prefetching
  unsigned gpr_pref_r;                // result "prefetching"
  unsigned gpr_psi_nb_buffer;         // buffer for data from nb nodes
  unsigned gpr_scratch_nb;
  unsigned gpr_scratch_sctr;
  unsigned gpr_counter_base;          // address of hw counter 0
  unsigned fpr_i;                     // constant "i"
  unsigned cr_it;
  unsigned stack_sz;
  std::vector<unsigned> gpr_load_psi; // psi load address
  std::vector<unsigned> gpr_pref_psi_d;
  std::vector<unsigned> fpr_U, fpr_hres, fpr_res, fpr_psi_pr;
  std::vector<unsigned> gpr_counter;     // "should be" counters (DMA)
  std::vector<unsigned> gpr_counter_hw;  // hw shadow counters (DMA)
  std::vector<unsigned> gpr_scratch_ctr; // used in counter comparison
  unsigned st_offs_save_regs;
  unsigned st_offs_scratch32;
  unsigned st_offs_res_addr;
  unsigned st_offs_res0;
  unsigned st_offs_ctr3;
  unsigned st_offs_vol;
  bool dont_upd_U;
  bool dont_upd_psi;
  bool dont_upd_r;
  unsigned pref_psi_kind;
  unsigned nb_array_offs;
  std::string name;
  std::string wait_loop_label;
  static const unsigned hsp_isign[3][2];
  static const unsigned hsp_col[3][2];
  static const unsigned pref_no   = 0x01;
  static const unsigned pref_pref = 0x02;
  static const unsigned pref_load = 0x03;
};



#endif
