import os

root = os.path.abspath(os.path.dirname(__file__))
attr_file = os.path.join(root, 'attributes.yaml')

license_header = '''
/*
See LICENSE for details
This file has been generated by CSR-BOX - {0}
Time of Generation: {1}
*/
'''

csr_str_temp = '''
                  `{0}: return "c{1}_{2}";'''

user_trap_csrs = [0x000, 0x004, 0x005, 0x040, 0x041, 0x042, 0x043, 0x044]

standard_csr_fields = [
    'description', 'address', 'priv_mode', 'reset-val', 'implemented', 'msb',
    'lsb', 'type', 'shadow', 'shadow_type', 'accessible', 'fields'
]

counters_list = ['mcycle','minstret','mhpmcounter3', 'mhpmcounter4',
        'mhpmcounter5', 'mhpmcounter6', 'mhpmcounter7', 'mhpmcounter8',
        'mhpmcounter9', 'mhpmcounter10' 'mhpmcounter11' 'mhpmcounter12'
        'mhpmcounter13' 'mhpmcounter14' 'mhpmcounter15' 'mhpmcounter16'
        'mhpmcounter17' 'mhpmcounter18' 'mhpmcounter19' 'mhpmcounter20'
        'mhpmcounter21' 'mhpmcounter22' 'mhpmcounter23' 'mhpmcounter24'
        'mhpmcounter25' 'mhpmcounter26' 'mhpmcounter27' 'mhpmcounter28'
        'mhpmcounter29' 'mhpmcounter30' 'mhpmcounter31' ]

time_csr = ['mtime', 'mtimeh', 'time', 'timeh']

temp_register = '''
    /*doc:reg: {0}*/
    Reg#(Bit#({1})) rg_{2} <- mkReg({3});
'''

temp_shadow_reg = '''
    /*doc:reg: {0}*/
    Reg#(Bit#({1})) rg_{2} = {3};
'''

temp_wire = '''
    /*doc:wire: */
    Wire#(Bit#({0})) rg_{1} <- mkDWire(0);
'''

temp_readOnlyRegister = '''
    /*doc:reg: {0}*/
    Reg#(Bit#({1})) rg_{2} = readOnlyReg({3});
'''

temp_wlrlReg = '''
    function Reg#(Bit#({1})) wlrlReg_{2}(Reg#(Bit#({4})) r);
        return (interface Reg;
            method Bit#({1}) _read = zeroExtend(r);
            method Action _write(Bit#({1}) x);
                r._write(truncate(x));
            endmethod
        endinterface);
    endfunction: wlrlReg_{2}

    /*doc:reg: {0}*/
    Reg#(Bit#({4})) rg_{2}_wlrl <- mkReg({3});
    Reg#(Bit#({1})) rg_{2} = wlrlReg_{2}(rg_{2}_wlrl);
'''

temp_warlReg = '''
    function Reg#(Bit#({1})) warlReg_{2}(Reg#(Bit#({1})) r);
        return (interface Reg;
            method Bit#({1}) _read = r;
            method Action _write(Bit#({1}) x);
                {4}
            endmethod
        endinterface);
    endfunction: warlReg_{2}

    /*doc:reg: {0}*/
    Reg#(Bit#({1})) rg_{2}_warl <- mkReg({3});
    Reg#(Bit#({1})) rg_{2} = warlReg_{2}(rg_{2}_warl);
'''

temp_warlReg_pmpaddr = '''
    function Reg#(Bit#({1})) warlReg_{2}(Reg#(Bit#({1})) r);
        return (interface Reg;
            method Bit#({1}) _read;
                if (rg_pmpcfg{5}_pmp{6}cfg[4]==1)
                    return (r | napot_mask);
                else
                    return (r & tor_mask);
            endmethod
            method Action _write(Bit#({1}) x);
                {4}
            endmethod
        endinterface);
    endfunction: warlReg_{2}

    /*doc:reg: {0}*/
    Reg#(Bit#({1})) rg_{2}_warl <- mkReg({3});
    Reg#(Bit#({1})) rg_{2} = warlReg_{2}(rg_{2}_warl);
'''

temp_method_shadow = '''
    method Action ma_read_{1} (Bit#({0}) _{1});
        rg_{1} <= _{1};
    endmethod
'''

temp_req_connection = '''
    let x{2} <- mkConnection({0}.mav_fwd_req,{1}.ma_core_req);'''

temp_prv_connection = '''
    mkConnection({0}.ma_upd_privilege, rg_prv);
    mkConnection({0}.ma_upd_virtual, rg_virtual);'''
temp_dbg_connection = '''
    mkConnection({0}.ma_upd_debug_mode, rg_debug_mode);'''

temp_dbg_connection = '''
    mkConnection({0}.ma_upd_debug_mode, rg_debug_mode);'''

temp_top_csr_connection = '''
    mkConnection({0}.ma_read_{1}, {2}.mv_csr_{1});'''

concat_temp = '''
    /*doc:reg: {0} */
    Reg#(Bit#({1})) rg_{2} = concatReg{3}({4});
'''

readonly_temp = ''' readOnlyReg({0}'d0) '''

address_temp = '''
`define {0} 12'h{1}'''

case_address_temp = '''
                  `{0}: {1} valid= True;'''

package_temp = '''
package {0};
   
import Vector           :: *;
import FIFOF            :: * ;
import DReg             :: * ;
import UniqueWrappers   :: * ;
import ConcatReg        :: * ;
import GetPut           :: * ;
import Connectable      :: * ;
import csr_types        :: * ;
import Assert           :: * ;
`include "csrbox.defines"
`include "Logger.bsv"
'''

interface_temp = '''
  // Interaface declaration
  interface Ifc_{0};
'''

methodv_dec_temp = '''
    method Bit#({0}) mv_csr_{1};'''
methoda_read_temp = '''
    method Action ma_read_{1} ({0});'''
method_station_generic = '''    
    /*doc:method : to receive the request from the core or previous node" */
    method Action ma_core_req(CSRReq req); 

    /*doc:method : to send response to core on a hit in this node" */
    method CSRResponse mv_core_resp;

    /*doc:method: fetch from core the prvilege mode */
    method Action ma_upd_privilege (Privilege_mode prv);
    
    /*doc:method: fetch from core the virtual mode */
    method Action ma_upd_virtual (Bit#(1) _virtual);
    '''

method_station_generic_debug = '''
    method Action ma_upd_debug_mode (Bit#(1) _dbg);
    '''

method_station_generic_debug = '''
    method Action ma_upd_debug_mode (Bit#(1) _dbg);
    '''

method_fwd_temp = '''
    /*doc:method: to forward the request to the next node on a miss in current node*/
    method ActionValue#(CSRReq) mav_fwd_req;
'''

method_top_def_temp = '''
    method mv_core_resp = CSRResponse{hit:anyhit, data: anydata 
        `ifdef rtldump , csr_updated: anyupdated `endif };
    method mv_prv = rg_prv;
    method mv_virtual = rg_virtual; '''

xret_mu = '''
    method ActionValue#(Bit#({0})) mav_upd_on_ret (Bit#(8) retype);
      Privilege_mode prv = unpack(retype[5:4]);
      Bool dret = (retype[3:0] == 'hb);
      Bit#(TSub#({0},1)) lv_epc = ?;

      {1}
      begin // only mret should show up
        rg_prv <= unpack({2}.mv_csr_mstatus[12:11]);
        {2}.ma_set_mstatus_mpie(1'b1);
        {2}.ma_set_mstatus_mie({2}.mv_csr_mstatus[7]);
        lv_epc = truncateLSB({3}.mv_csr_mepc);

        if (lv_misa_u == 1)
          {2}.ma_set_mstatus_mpp(pack(User));
        else
          {2}.ma_set_mstatus_mpp(pack(Machine));

        if ({2}.mv_csr_mstatus[12:11] != '1)
          {2}.ma_set_mstatus_mprv(0);

        if (lv_misa_c == 0)
          lv_epc[0] = 0;
      end
      return {{lv_epc, 1'b0}};
    endmethod
'''

xret_msu = '''
    method ActionValue#(Bit#({0})) mav_upd_on_ret (Bit#(8) retype);
      Privilege_mode prv = unpack(retype[5:4]);
      Bool dret = (retype[3:0] == 'hb);
      Bit#(TSub#({0},1)) lv_epc = ?;

      {1}
      begin
        if (prv == Supervisor) begin
          {2}.ma_set_mstatus_spie(1'b1);
          {2}.ma_set_mstatus_sie({2}.mv_csr_mstatus[5]);
          rg_prv <= unpack(zeroExtend({2}.mv_csr_mstatus[8]));
          lv_epc = truncateLSB({3}.mv_csr_sepc);
          if (lv_misa_u == 1)
            {2}.ma_set_mstatus_spp(0);
          else
            {2}.ma_set_mstatus_spp(1);
          {2}.ma_set_mstatus_mprv(0);
        end
        if (prv == Machine) begin
          rg_prv <= unpack({2}.mv_csr_mstatus[12:11]);
          {2}.ma_set_mstatus_mpie(1'b1);
          {2}.ma_set_mstatus_mie({2}.mv_csr_mstatus[7]);
          lv_epc = truncateLSB({3}.mv_csr_mepc);

          if (lv_misa_u == 1)
            {2}.ma_set_mstatus_mpp(pack(User));
          else
            {2}.ma_set_mstatus_mpp(pack(Machine));

          if ({2}.mv_csr_mstatus[12:11] != '1)
            {2}.ma_set_mstatus_mprv(0);

        end
      end
      if (lv_misa_c == 0)
        lv_epc[0] = 0;
      return {{lv_epc, 1'b0}};
    endmethod
'''

xret_mhsu32 = '''
    method ActionValue#(Bit#({0})) mav_upd_on_ret (Bit#(8) retype);
      Privilege_mode prv = unpack(retype[5:4]);
      Bool dret = (retype[3:0] == 'hb);
      Bit#(TSub#({0},1)) lv_epc = ?;

      {1}
      begin
        if (prv == Supervisor) begin
          lv_epc = rg_virtual == 1? truncateLSB({7}.mv_csr_vsepc): truncateLSB({2}.mv_csr_sepc);
          let status = rg_virtual == 1? {3}.mv_csr_vsstatus:{4}.mv_csr_mstatus;
          Privilege_mode prev_prv = unpack(zeroExtend(status[8])); // (v)sstatus_spp
          rg_prv <= prev_prv;
          if (rg_virtual == 1) begin
            {3}.ma_set_vsstatus_sie(status[5]); // write spie
            {3}.ma_set_vsstatus_spie(1);
            {3}.ma_set_vsstatus_spp(0);
          end
          else begin
            let prev_virt = {5}.mv_csr_hstatus[7]; // read SPV
            rg_virtual <= prev_virt;
            if (prev_prv != Machine) 
              grp1.ma_set_mstatus_mprv(0);
            {4}.ma_set_mstatus_sie(status[5]);
            {4}.ma_set_mstatus_spie(1);
            {4}.ma_set_mstatus_spp(0);
            {5}.ma_set_hstatus_spv(0);
          end
        end
        if (prv == Machine) begin
          let prev_virt = {5}.mv_csr_mstatush[7]; // read MPV
          rg_virtual <= prev_virt;
          rg_prv <= unpack({4}.mv_csr_mstatus[12:11]);
          {4}.ma_set_mstatus_mpie(1'b1);
          {4}.ma_set_mstatus_mie(grp1.mv_csr_mstatus[7]);
          lv_epc = truncateLSB({6}.mv_csr_mepc);
          if (lv_misa_u == 1)
            {4}.ma_set_mstatus_mpp(pack(User));
          else
            {4}.ma_set_mstatus_mpp(pack(Machine));
          if ({4}.mv_csr_mstatus[12:11] != '1)
            {4}.ma_set_mstatus_mprv(0);
          {5}.ma_set_mstatush_mpv(0);
        end
      end
      if (lv_misa_c == 0)
        lv_epc[0] = 0;
      return {{lv_epc, 1'b0}};
    endmethod
'''
xret_mhsu = '''
    method ActionValue#(Bit#({0})) mav_upd_on_ret (Bit#(8) retype);
      Privilege_mode prv = unpack(retype[5:4]);
      Bool dret = (retype[3:0] == 'hb);
      Bit#(TSub#({0},1)) lv_epc = ?;

      {1}
      begin
        if (prv == Supervisor) begin
          lv_epc = rg_virtual == 1? truncateLSB({7}.mv_csr_vsepc): truncateLSB({2}.mv_csr_sepc);
          let status = rg_virtual == 1? {3}.mv_csr_vsstatus:{4}.mv_csr_mstatus;
          Privilege_mode prev_prv = unpack(zeroExtend(status[8])); // (v)sstatus_spp
          rg_prv <= prev_prv;
          if (rg_virtual == 1) begin
            {3}.ma_set_vsstatus_sie(status[5]); // write spie
            {3}.ma_set_vsstatus_spie(1);
            {3}.ma_set_vsstatus_spp(0);
          end
          else begin
            let prev_virt = {5}.mv_csr_hstatus[7]; // read SPV
            rg_virtual <= prev_virt;
            if (prev_prv != Machine) 
              grp1.ma_set_mstatus_mprv(0);
            {4}.ma_set_mstatus_sie(status[5]);
            {4}.ma_set_mstatus_spie(1);
            {4}.ma_set_mstatus_spp(0);
            {5}.ma_set_hstatus_spv(0);
          end
        end
        if (prv == Machine) begin
          let prev_virt = {4}.mv_csr_mstatus[39]; // read MPV
          rg_virtual <= prev_virt;
          rg_prv <= unpack({4}.mv_csr_mstatus[12:11]);
          {4}.ma_set_mstatus_mpie(1'b1);
          {4}.ma_set_mstatus_mie(grp1.mv_csr_mstatus[7]);
          lv_epc = truncateLSB({6}.mv_csr_mepc);
          if (lv_misa_u == 1)
            {4}.ma_set_mstatus_mpp(pack(User));
          else
            {4}.ma_set_mstatus_mpp(pack(Machine));
          if ({4}.mv_csr_mstatus[12:11] != '1)
            {4}.ma_set_mstatus_mprv(0);
          {4}.ma_set_mstatus_mpv(0);
        end
      end
      if (lv_misa_c == 0)
        lv_epc[0] = 0;
      return {{lv_epc, 1'b0}};
    endmethod
'''

dret_temp = '''
      if (dret) begin
        dynamicAssert(rg_debug_mode==1,"Executing DRET when not in Debug Mode");
        lv_epc = truncateLSB({0}.mv_csr_dpc);
        rg_debug_mode <= 0;
        rg_prv <= unpack({1}.mv_csr_dcsr[1:0]);
        if ({1}.mv_csr_dcsr[1:0] < 3)
          {2}.ma_set_mstatus_mprv(0);

      end
      else
'''
trap_mu = '''
    method ActionValue#(Bit#({0})) mav_upd_on_trap(Bit#(`causesize) cause, Bit#({0}) pc, Bit#({0}) tval);
      Bit#(TSub#(`causesize,1)) lv_cause = truncate(cause);
      Bit#(1) lv_trap_type = truncateLSB(cause);
      Bit#({0}) lv_tvec = ?;
      Bit#(2) lv_trapmode = 0;
      Privilege_mode prv = Machine;
      
      `logLevel( csrbox, 0, $format("Taking Trap. Cause:%h,PC:%h,TVAL:%h",cause, pc, tval))
      `logLevel( csrbox, 0, $format("Trap delegated to ",fshow(prv)))
    
      {6}
      begin
        rg_prv <= Machine;
        {1}.ma_set_mtval(tval);
        {2}.ma_set_mepc(pc);
        {3}.ma_set_mcause({{lv_trap_type, 'd0, lv_cause}});
        {4}.ma_set_mstatus_mie(1'b0);
        {4}.ma_set_mstatus_mpp(pack(rg_prv));
        {4}.ma_set_mstatus_mpie({4}.mv_csr_mstatus[3]);
        lv_trapmode = truncate({5}.mv_csr_mtvec);
        lv_tvec = {{truncateLSB({5}.mv_csr_mtvec), 2'b0}};

        if ( lv_trapmode == 1 && lv_trap_type == 1)
          lv_tvec =  lv_tvec + {{zeroExtend(lv_cause),2'b0}};
      end
    
      `logLevel( csrbox, 0, $format("TVEC:%h",lv_tvec))
      return lv_tvec;
    endmethod
        
'''

trap_msu = '''
    method ActionValue#(Bit#({0})) mav_upd_on_trap(Bit#(`causesize) cause, Bit#({0}) pc, Bit#({0}) tval);
      Bit#(TSub#(`causesize,1)) lv_cause = truncate(cause);
      Bit#(1) lv_trap_type = truncateLSB(cause);
      Bit#({0}) lv_tvec = ?;
      Bit#(2) lv_trapmode = 0;
      Privilege_mode prv = Machine;
      let medeleg = {1}.mv_csr_medeleg;
      let mideleg = {2}.mv_csr_mideleg;
      Bool delegateM = (truncate(mideleg >> lv_cause) & lv_trap_type) == 1 ||
                       (truncate(medeleg >> lv_cause) & ~lv_trap_type) == 1 ;
      if (delegateM && (pack(rg_prv) <= pack(Supervisor)) && lv_misa_s == 1)
        prv = Supervisor;
      
      `logLevel( csrbox, 0, $format("Taking Trap. Cause:%h,PC:%h,TVAL:%h",cause, pc, tval))
      `logLevel( csrbox, 0, $format("Trap delegated to ",fshow(prv)))

      {12}
      begin

        if (prv == Supervisor) begin
          rg_prv <= Supervisor;
          {3}.ma_set_stval(tval);
          {4}.ma_set_sepc(pc);
          {5}.ma_set_scause({{lv_trap_type, 'd0, lv_cause}});
          {6}.ma_set_mstatus_sie(0);
          {6}.ma_set_mstatus_spp(truncate(pack(rg_prv)));
          {6}.ma_set_mstatus_spie({6}.mv_csr_mstatus[1]);
          lv_trapmode = truncate({7}.mv_csr_stvec);
          lv_tvec = {{truncateLSB({7}.mv_csr_stvec), 2'b0}};
        end

        if (prv == Machine) begin
          rg_prv <= Machine;
          {8}.ma_set_mtval(tval);
          {9}.ma_set_mepc(pc);
          {10}.ma_set_mcause({{lv_trap_type, 'd0, lv_cause}});
          {6}.ma_set_mstatus_mie(1'b0);
          {6}.ma_set_mstatus_mpp(pack(rg_prv));
          {6}.ma_set_mstatus_mpie({6}.mv_csr_mstatus[3]);
          lv_trapmode = truncate({11}.mv_csr_mtvec);
          lv_tvec = {{truncateLSB({11}.mv_csr_mtvec), 2'b0}};
        end

        if ( lv_trapmode == 1 && lv_trap_type == 1)
          lv_tvec =  lv_tvec + {{zeroExtend(lv_cause),2'b0}};
      end 
      `logLevel( csrbox, 0, $format("TVEC:%h",lv_tvec))
      return lv_tvec;
    endmethod
        
'''

trap_mhsu32 = '''
    method ActionValue#(Bit#({0})) mav_upd_on_trap(Bit#(`causesize) cause,
    Bit#({0}) pc, Bit#({0}) tval, Bit#({0}) tval2);
      Bit#(TSub#(`causesize,1)) lv_cause = truncate(cause);
      Bit#(1) lv_trap_type = truncateLSB(cause);
      Bit#({0}) lv_tvec = ?;
      Bit#(2) lv_trapmode = 0;
      Privilege_mode prv = Machine;
      let medeleg = {1}.mv_csr_medeleg;
      let mideleg = {2}.mv_csr_mideleg;
      let hedeleg = {3}.mv_csr_hedeleg;
      let hideleg = {4}.mv_csr_hideleg;

      Bool hsdeleg = False;
      Bool vsdeleg = False;
      
      `logLevel( csrbox, 0, $format("Taking Trap. Cause:%h,PC:%h,TVAL:%h TVAL2:%h",cause, pc, tval, tval2))
      `logLevel( csrbox, 0, $format("Trap delegated to ",fshow(prv)))

      Bool delegateM = (truncate(mideleg >> lv_cause) & lv_trap_type) == 1 ||
                       (truncate(medeleg >> lv_cause) & ~lv_trap_type) == 1 ;
      Bool delegateH = (truncate(hideleg >> lv_cause) & lv_trap_type) == 1 ||
                       (truncate(hedeleg >> lv_cause) & ~lv_trap_type) == 1;
      if (delegateM && (pack(rg_prv) <= pack(Supervisor)) && lv_misa_s == 1)
        prv = Supervisor;

      if (delegateM && (pack(rg_prv) <= pack(Supervisor)) && (lv_misa_h == 1))
        hsdeleg = True;
      if (delegateM && delegateH && rg_virtual == 1 && (pack(rg_prv) <= pack(Supervisor)))
        vsdeleg= True;
      
      `logLevel( csrbox, 0, $format("Taking Trap. Cause:%h,PC:%h,TVAL:%h",cause, pc, tval))
      `logLevel( csrbox, 0, $format("Trap delegated to ",fshow(prv)))

      {24}
      begin
      
        if (prv == Supervisor) begin
          rg_prv <= Supervisor;
             
          if( vsdeleg == True) begin					//VS
            {5}.ma_set_vstval(tval);
            {6}.ma_set_vsepc(pc);
            if (lv_trap_type == 1)
              lv_cause = lv_cause -1;
            {7}.ma_set_vscause({{lv_trap_type, 'd0, lv_cause}});
            lv_trapmode = truncate({8}.mv_csr_vstvec);
            lv_tvec = {{truncateLSB({8}.mv_csr_vstvec), 2'b0}};
            {9}.ma_set_vsstatus_sie(1'b0);
            {9}.ma_set_vsstatus_spp(truncate(pack(rg_prv)));
            {9}.ma_set_vsstatus_spie({9}.mv_csr_vsstatus[1]);
          end
          else begin // HS mode by default
            rg_virtual <= 0;
            {10}.ma_set_scause({{lv_trap_type, 'd0, lv_cause}});
            {11}.ma_set_sepc(pc);
            {12}.ma_set_stval(tval);
            lv_trapmode = truncate({13}.mv_csr_stvec);
            lv_tvec = {{truncateLSB({13}.mv_csr_stvec), 2'b0}};
            
            {14}.ma_set_htval({21}.mv_csr_mtval2);
            {15}.ma_set_htinst({15}.mv_csr_htinst);
            if (rg_virtual == 1)
              {16}.ma_set_hstatus_spvp(truncate(pack(rg_prv)));
            // set gva to 0 for illegal, e-calls and virt inst traps
            if (lv_trapmode == 0 && (lv_cause == 2 || (lv_cause >=8 && lv_cause <= 11) || lv_cause == 22 || (rg_virtual == 0 && (lv_cause >= 12 && lv_cause <= 15)) ))
              {16}.ma_set_hstatus_gva(0);
            else
              {16}.ma_set_hstatus_gva(1);
            {16}.ma_set_hstatus_gva({16}.mv_csr_hstatus[6]);
            {16}.ma_set_hstatus_spv(pack(rg_virtual)); 
            {17}.ma_set_mstatus_sie(1'b0);
            {17}.ma_set_mstatus_spp(truncate(pack(rg_prv)));
            {17}.ma_set_mstatus_spie({17}.mv_csr_mstatus[1]);
          end
        end
        else

        if (prv == Machine) begin
          rg_prv <= Machine;
          {18}.ma_set_mtval(tval);
          {19}.ma_set_mepc(pc);
          {20}.ma_set_mcause({{lv_trap_type, 'd0, lv_cause}});
          {17}.ma_set_mstatus_mie(1'b0);
          {17}.ma_set_mstatus_mpp(pack(rg_prv));
          {17}.ma_set_mstatus_mpie({17}.mv_csr_mstatus[3]); 
          rg_virtual <= 0;
          {21}.ma_set_mtval2(tval2);
          {22}.ma_set_mtinst({22}.mv_csr_mtinst);         
          {25}.ma_set_mstatush_mpv(pack(rg_virtual));
          // set gva to 0 for illegal, e-calls and virt inst traps
          if (lv_trapmode == 0 && (lv_cause == 2 || (lv_cause >=8 && lv_cause <= 11) || lv_cause == 22))
            {25}.ma_set_mstatush_gva(0);
          else
            {25}.ma_set_mstatush_gva(1);
          lv_trapmode = truncate({23}.mv_csr_mtvec);
          lv_tvec = {{truncateLSB({23}.mv_csr_mtvec),2'b0}};
        end

        if ( lv_trapmode == 1 && lv_trap_type == 1)
          lv_tvec =  lv_tvec + {{zeroExtend(lv_cause),2'b0}};
      end    
      `logLevel( csrbox, 0, $format("TVEC:%h lv_cause: 'd%d rg_virtual: %d lv_trapmode: %d",lv_tvec,lv_cause,rg_virtual, lv_trapmode))
      return lv_tvec;
    endmethod
        
'''

trap_mhsu = '''
    method ActionValue#(Bit#({0})) mav_upd_on_trap(Bit#(`causesize) cause,
    Bit#({0}) pc, Bit#({0}) tval, Bit#({0}) tval2);
      Bit#(TSub#(`causesize,1)) lv_cause = truncate(cause);
      Bit#(1) lv_trap_type = truncateLSB(cause);
      Bit#({0}) lv_tvec = ?;
      Bit#(2) lv_trapmode = 0;
      Privilege_mode prv = Machine;
      let medeleg = {1}.mv_csr_medeleg;
      let mideleg = {2}.mv_csr_mideleg;
      let hedeleg = {3}.mv_csr_hedeleg;
      let hideleg = {4}.mv_csr_hideleg;

      Bool hsdeleg = False;
      Bool vsdeleg = False;

      Bool delegateM = (truncate(mideleg >> lv_cause) & lv_trap_type) == 1 ||
                       (truncate(medeleg >> lv_cause) & ~lv_trap_type) == 1 ;
      Bool delegateH = (truncate(hideleg >> lv_cause) & lv_trap_type) == 1 ||
                       (truncate(hedeleg >> lv_cause) & ~lv_trap_type) == 1;
      if (delegateM && (pack(rg_prv) <= pack(Supervisor)) && lv_misa_s == 1)
        prv = Supervisor;

      if (delegateM && (pack(rg_prv) <= pack(Supervisor)) && (lv_misa_h == 1))
        hsdeleg = True;
      if (delegateM && delegateH && rg_virtual == 1 && (pack(rg_prv) <= pack(Supervisor)))
        vsdeleg= True;
      
      `logLevel( csrbox, 0, $format("Taking Trap. Cause:%h,PC:%h,TVAL:%h TVAL2:%h",cause, pc, tval, tval2))
      `logLevel( csrbox, 0, $format("Trap delegated to ",fshow(prv)))

      {24}
      begin
      
        if (prv == Supervisor) begin
          rg_prv <= Supervisor;
             
          if( vsdeleg == True) begin					//VS
            {5}.ma_set_vstval(tval);
            {6}.ma_set_vsepc(pc);
            if (lv_trap_type == 1)
              lv_cause = lv_cause -1;
            {7}.ma_set_vscause({{lv_trap_type, 'd0, lv_cause}});
            lv_trapmode = truncate({8}.mv_csr_vstvec);
            lv_tvec = {{truncateLSB({8}.mv_csr_vstvec), 2'b0}};
            {9}.ma_set_vsstatus_sie(1'b0);
            {9}.ma_set_vsstatus_spp(truncate(pack(rg_prv)));
            {9}.ma_set_vsstatus_spie({9}.mv_csr_vsstatus[1]);
          end
          else begin // HS mode by default
            rg_virtual <= 0;
            {10}.ma_set_scause({{lv_trap_type, 'd0, lv_cause}});
            {11}.ma_set_sepc(pc);
            {12}.ma_set_stval(tval);
            lv_trapmode = truncate({13}.mv_csr_stvec);
            lv_tvec = {{truncateLSB({13}.mv_csr_stvec), 2'b0}};
            
            {14}.ma_set_htval({21}.mv_csr_mtval2);
            {15}.ma_set_htinst({15}.mv_csr_htinst);
            if (rg_virtual == 1)
              {16}.ma_set_hstatus_spvp(truncate(pack(rg_prv)));
            // set gva to 0 for illegal, e-calls and virt inst traps
            if (lv_trapmode == 0 && (lv_cause == 2 || (lv_cause >=8 && lv_cause <= 11) || lv_cause == 22))
              {16}.ma_set_hstatus_gva(0);
            else
              {16}.ma_set_hstatus_gva(1);
            {16}.ma_set_hstatus_spv(pack(rg_virtual)); 
            {17}.ma_set_mstatus_sie(1'b0);
            {17}.ma_set_mstatus_spp(truncate(pack(rg_prv)));
            {17}.ma_set_mstatus_spie({17}.mv_csr_mstatus[1]);
          end
        end
        else

        if (prv == Machine) begin
          rg_prv <= Machine;
          {18}.ma_set_mtval(tval);
          {19}.ma_set_mepc(pc);
          {20}.ma_set_mcause({{lv_trap_type, 'd0, lv_cause}});
          {17}.ma_set_mstatus_mie(1'b0);
          {17}.ma_set_mstatus_mpp(pack(rg_prv));
          {17}.ma_set_mstatus_mpie({17}.mv_csr_mstatus[3]); 
          rg_virtual <= 0;
          {21}.ma_set_mtval2(tval2);
          {22}.ma_set_mtinst({22}.mv_csr_mtinst);         
          {17}.ma_set_mstatus_mpv(pack(rg_virtual));
          // set gva to 0 for illegal, e-calls and virt inst traps
          if (lv_trapmode == 0 && (lv_cause == 2 || (lv_cause >=8 && lv_cause <= 11) || lv_cause == 22 || (rg_virtual == 0 && (lv_cause >= 12 && lv_cause <= 15)) ))
            {17}.ma_set_mstatus_gva(0);
          else
            {17}.ma_set_mstatus_gva(1);
          lv_trapmode = truncate({23}.mv_csr_mtvec);
          lv_tvec = {{truncateLSB({23}.mv_csr_mtvec),2'b0}};
        end

        if ( lv_trapmode == 1 && lv_trap_type == 1)
          lv_tvec =  lv_tvec + {{zeroExtend(lv_cause),2'b0}};
      end    
      `logLevel( csrbox, 0, $format("TVEC:%h lv_cause: 'd%d rg_virtual: %d lv_trapmode: %d",lv_tvec,lv_cause,rg_virtual, lv_trapmode))
      return lv_tvec;
    endmethod
        
'''

trap_debug = '''
      if ( (lv_trap_type == 0 && (lv_cause == `halt_ebreak || 
                                lv_cause == `halt_trigger ||
                                lv_cause == `halt_step ||
                                lv_cause == `halt_reset ))
            || (lv_trap_type == 1 && lv_cause == `debug_interrupt)) begin
        {0}.ma_set_dpc(pc);
        {1}.ma_set_dcsr_cause(lv_trap_type == 1? 3:truncate(lv_cause));
        rg_debug_mode <= 1;
        {1}.ma_set_dcsr_prv(pack(rg_prv));
        rg_prv <= Machine;
        lv_tvec = `debug_parking_loop;
      end
      else if(rg_debug_mode == 1)
        lv_tvec = (lv_cause == 3 && lv_trap_type == 0)?`debug_parking_loop: `debug_parking_loop + 8;
      else
'''

method_top_debug_dec = '''
    method Bit#(1) mv_debug_mode;
    method Bit#(1) mv_stop_count;
    method Bit#(1) mv_stop_timer;
'''
method_top_debug_def = '''
    method mv_debug_mode = rg_debug_mode;
    method mv_stop_count = pack(rg_debug_mode) & {0}.mv_csr_dcsr[10];
    method mv_stop_timer = pack(rg_debug_mode) & {0}.mv_csr_dcsr[9];
'''
        
end_interface_temp = '''
  endinterface
'''
module_temp = '''
  //Module Declarations
`ifdef csrbox_grp_noinline
  (*synthesize*)
  
  (*conflict_free="ma_core_req,mv_core_resp"*)
{1}
`endif
  module mk_{0}{2}(Ifc_{0});

    String csrbox = "";
'''
top_module_temp = '''
  //Module Declarations
`ifdef csrbox_noinline
  (*synthesize*)
  
  (*conflict_free="ma_core_req,mv_core_resp"*)
{1}
`endif
  module mk_{0}{2}(Ifc_{0});

    String csrbox = "";
'''

methodv_def_temp = '''
    method mv_csr_{0} = {1}{2};
'''

methoda_top_temp = '''
    method {0} = {1}.{0};'''

end_module_temp = '''
  endmodule '''

endcase_temp = '''
            default: begin
                rg_resp_to_core <= CSRResponse{hit: True, data: 0 `ifdef rtldump , csr_updated : False `endif };
            end
        endcase
        endmethod
    '''
endcase_fwd_temp = '''
            default: begin
                ff_fwd_request.enq(req);
                `logLevel( {0}, 1, $format("{0}: fwding req to next group"))
                rg_resp_to_core <= CSRResponse{{hit: False, data: 0 `ifdef rtldump , csr_updated : False `endif }};
            end
        endcase
        endmethod
    '''

end_package_temp = '''
endpackage 
'''

func_temp = '''
    function Bit#({0}) fn_csr_op (Bit#({0}) writedata, Bit#({0}) readdata, Bit#(2) op);
        if(op == 'd1)
    	    return writedata;
        else if(op == 'd2)
            return (writedata|readdata);
        else
            return (~writedata & readdata);
    endfunction
  '''
func_address = ''' 
    function Bit#(12) fn_address_virtual(Bit#(12) csr_address, Bit#(1) wr_virtual);
        let addr = csr_address;
        if (wr_virtual == 1) begin
          case(csr_address)
            `SCAUSE: addr = `VSCAUSE ;
            `STVAL: addr = `VSTVAL ;
            `SSCRATCH: addr = `VSSCRATCH ;
            `STVAL: addr = `VSTVEC ;
            `SEPC: addr = `VSEPC ;
            `SATP: addr = `VSATP ;
            `STVEC: addr = `VSTVEC ;             
            `SIE: addr = `VSIE ;             
            `SIP: addr = `VSIP ;
            `SSTATUS: addr = `VSSTATUS;
          endcase
        end
        return addr;
   endfunction
   '''
func_external = '''
  function Reg#(Bit#({0})) extInterruptReg(Reg#(Bit#({0})) r1, Reg#(Bit#({0})) r2);
    return (interface Reg;
      method Bit#({0}) _read = r1 | r2;
      method Action _write(Bit#({0}) x);
        r1._write(x);
			endmethod
    endinterface);
  endfunction
  '''
func_decoder = '''
    function Bool address_valid(Bit#(12) addr, Bit#(26) misa);
    Bool valid=False;
    case(addr)
   '''

func_csr_to_csr = '''
    function String fn_csr_to_str(Bit#(12) addr);
    case(addr)
    '''

method_csr_req_def_temp = ''' 
        method Action ma_core_req(CSRReq req);
        `logLevel( {0}, 1, $format("{0}: received req: ", fshow(req)))
        Bit#(2) op = req.funct3; '''

method_case_req = '''
        case (req.csr_address) '''

method_generic_def_temp = '''
    method mv_core_resp = rg_resp_to_core;

    method Action ma_upd_privilege (Privilege_mode prv);
        wr_prv <= prv;
    endmethod
    
    method Action ma_upd_virtual (Bit#(1) _virtual);
         wr_virtual <= _virtual;
    endmethod'''
method_generic_debug_def_temp = '''
    method Action ma_upd_debug_mode (Bit#(1) _dbg);
        wr_debug_mode <= _dbg;
    endmethod'''
method_generic_debug_def_temp = '''
    method Action ma_upd_debug_mode (Bit#(1) _dbg);
        wr_debug_mode <= _dbg;
    endmethod'''

method_fwd_def_temp = '''
        method ActionValue#(CSRReq) mav_fwd_req;
            ff_fwd_request.deq;
            return ff_fwd_request.first();
        endmethod
'''
case_def = '''
            `{0} : begin
                Bit#({2}) readdata = zeroExtend(rg_{1});
                rg_resp_to_core <= CSRResponse{{hit:True, data: readdata
                    `ifdef rtldump ,csr_updated: True `endif }};
                let word = fn_csr_op(req.writedata, readdata, op);
                
                {3} rg_{1} <= truncate(word);
            end
'''
case_def_vs_set = '''
            
            `{0} : begin
            if (wr_virtual == 1) begin
                Bit#({2}) readdata = zeroExtend(rg_{1});
                rg_resp_to_core <= CSRResponse{{hit:True, data: readdata
                    `ifdef rtldump ,csr_updated: True `endif }};
                let word = fn_csr_op(req.writedata, readdata, op);
                
                {3} rg_{1} <= truncate(word);
            end
            else if (wr_virtual == 0) begin
                Bit#({2}) readdata = zeroExtend(rg_{4});
                rg_resp_to_core <= CSRResponse{{hit:True, data: readdata
                    `ifdef rtldump ,csr_updated: True `endif }};
                let word = fn_csr_op(req.writedata, readdata, op);
                
                {3} rg_{4} <= truncate(word);
            end
            end
'''

case_def_ro = '''
            `{0} : begin
                Bit#({2}) readdata = zeroExtend(rg_{1});
                rg_resp_to_core <= CSRResponse{{hit:True, data: readdata `ifdef rtldump , csr_updated : False `endif }};
            end
'''
csrreq_struct_temp = '''
    typedef struct {{
        Bit#(12) csr_address;
        Bit#({0}) writedata;
        Bit#(2) funct3;
        {1}
    }} CSRReq deriving(Bits, FShow, Eq);

    typedef struct{{
        Bool hit;
        Bit#({0})  data;
    `ifdef rtldump
        Bool csr_updated;
    `endif
    }} CSRResponse deriving(Bits, Eq, FShow);

    typedef enum {{Machine = 3, Hypervisor=2, Supervisor = 1, User = 0}} Privilege_mode deriving(Bits, Eq, FShow);

'''
pmp_masks_grain0 = '''
    Bit#({0}) napot_mask = 0;
    Bit#({0}) tor_mask = '1;
'''

pmp_masks_grain1 = '''
    Bit#(`pmp_grain) tor = 0;
    Bit#({0}) napot_mask = 0;
    Bit#({0}) tor_mask = signExtend({{1'b1,tor}});
'''

pmp_masks_grain2 = '''
    Bit#(TSub#(`pmp_grain,1)) napot= '1;
    Bit#(`pmp_grain) tor = 0;
    Bit#({0}) napot_mask = zeroExtend(napot);
    Bit#({0}) tor_mask = signExtend({{1'b1,tor}});
'''

other_vars_temp = '''

    /*doc:wire: holds the response of this group for a csr operation request,
    for one cycle, wire is used for low latency*/
    Wire#(CSRResponse) rg_resp_to_core <- mkDWire(CSRResponse{hit:False, data:0
        `ifdef rtldump , csr_updated: False `endif });

    /*doc:fifo: fifo to forward the core request to the next group on a miss*/
    FIFOF#(CSRReq) ff_fwd_request <- mkFIFOF();

    /*doc:wire: holds the current privilege mode of the hart*/
    Wire#(Privilege_mode) wr_prv <- mkWire();
   
    /*doc:wire: holds the current state of the vs bit of the hart*/
    Wire#(Bit#(1)) wr_virtual <- mkWire();
'''

other_vars_debug_temp = '''
    Wire#(Bit#(1)) wr_debug_mode <- mkWire();
'''

other_vars_debug_temp = '''
    Wire#(Bit#(1)) wr_debug_mode <- mkWire();
'''

check_hit_temp = '''
    Bool anyhit = {0};
    Bit#({2}) anydata = {1};
`ifdef rtldump
    Bool anyupdated = {3};
`endif
'''

method_top_generic = '''    
    /*doc:method : to receive the request from the core or previous node" */
    method Action ma_core_req(CSRReq req); 

    /*doc:method : to send response to core on a hit in this node" */
    method CSRResponse mv_core_resp;

    method ActionValue#(Bit#({0})) mav_upd_on_ret (Bit#(8) retype);
    
    method ActionValue#(Bit#({0})) mav_upd_on_trap(Bit#(`causesize) cause, Bit#({0}) pc, Bit#({0}) tval);

    method Privilege_mode mv_prv;
    
    method Bit#(1) mv_virtual;


'''

method_top_generic_h = '''    
    /*doc:method : to receive the request from the core or previous node" */
    method Action ma_core_req(CSRReq req); 

    /*doc:method : to send response to core on a hit in this node" */
    method CSRResponse mv_core_resp;

    method ActionValue#(Bit#({0})) mav_upd_on_ret (Bit#(8) retype);
    
    method ActionValue#(Bit#({0})) mav_upd_on_trap(Bit#(`causesize) cause, Bit#({0}) pc, Bit#({0}) tval, Bit#({0}) tval2);

    method Privilege_mode mv_prv;
    
    method Bit#(1) mv_virtual;


'''

pmp_ifc = '''
    method Vector#({0}, Bit#(8)) mv_pmpcfg;
    method Vector#({0}, Bit#({1})) mv_pmpaddr;'''

pmpaddr_def = '''
    method Vector#({0}, Bit#({1})) mv_pmpaddr;
        Vector#({0}, Bit#({1})) lv_pmpaddr;
{2}
        return lv_pmpaddr;
    endmethod:mv_pmpaddr
'''
pmpcfg_def = '''
    method Vector#({0}, Bit#(8)) mv_pmpcfg;
        Vector#({0}, Bit#(8)) lv_pmpcfg;
{1}
        return lv_pmpcfg;
    endmethod:mv_pmpcfg
'''
same_groups_rv32 = [
        ('SSTATUS', 'MSTATUS'),
        ('USTATUS', 'MSTATUS'),
        ('MSTATUS', 'FCSR'),
        ('FRM', 'FCSR'),
        ('FFLAGS', 'FCSR'),
        ('MHPMCOUNTER3', 'MHPMCOUNTER3H'),
        ('MHPMCOUNTER4', 'MHPMCOUNTER4H'),
        ('MHPMCOUNTER5', 'MHPMCOUNTER5H'),
        ('MHPMCOUNTER6', 'MHPMCOUNTER6H'),
        ('MHPMCOUNTER7', 'MHPMCOUNTER7H'),
        ('MHPMCOUNTER8', 'MHPMCOUNTER8H'),
        ('MHPMCOUNTER9', 'MHPMCOUNTER9H'),
        ('MHPMCOUNTER10', 'MHPMCOUNTER10H'),
        ('MHPMCOUNTER11', 'MHPMCOUNTER11H'),
        ('MHPMCOUNTER12', 'MHPMCOUNTER12H'),
        ('MHPMCOUNTER13', 'MHPMCOUNTER13H'),
        ('MHPMCOUNTER14', 'MHPMCOUNTER14H'),
        ('MHPMCOUNTER15', 'MHPMCOUNTER15H'),
        ('MHPMCOUNTER16', 'MHPMCOUNTER16H'),
        ('MHPMCOUNTER17', 'MHPMCOUNTER17H'),
        ('MHPMCOUNTER18', 'MHPMCOUNTER18H'),
        ('MHPMCOUNTER19', 'MHPMCOUNTER19H'),
        ('MHPMCOUNTER20', 'MHPMCOUNTER20H'),
        ('MHPMCOUNTER21', 'MHPMCOUNTER21H'),
        ('MHPMCOUNTER22', 'MHPMCOUNTER22H'),
        ('MHPMCOUNTER23', 'MHPMCOUNTER23H'),
        ('MHPMCOUNTER24', 'MHPMCOUNTER24H'),
        ('MHPMCOUNTER25', 'MHPMCOUNTER25H'),
        ('MHPMCOUNTER26', 'MHPMCOUNTER26H'),
        ('MHPMCOUNTER27', 'MHPMCOUNTER27H'),
        ('MHPMCOUNTER28', 'MHPMCOUNTER28H'),
        ('MHPMCOUNTER29', 'MHPMCOUNTER29H'),
        ('MHPMCOUNTER30', 'MHPMCOUNTER30H'),
        ('MHPMCOUNTER31', 'MHPMCOUNTER31H'),
        ('HPMCOUNTER3', 'HPMCOUNTER3H'),
        ('HPMCOUNTER4', 'HPMCOUNTER4H'),
        ('HPMCOUNTER5', 'HPMCOUNTER5H'),
        ('HPMCOUNTER6', 'HPMCOUNTER6H'),
        ('HPMCOUNTER7', 'HPMCOUNTER7H'),
        ('HPMCOUNTER8', 'HPMCOUNTER8H'),
        ('HPMCOUNTER9', 'HPMCOUNTER9H'),
        ('HPMCOUNTER10', 'HPMCOUNTER10H'),
        ('HPMCOUNTER11', 'HPMCOUNTER11H'),
        ('HPMCOUNTER12', 'HPMCOUNTER12H'),
        ('HPMCOUNTER13', 'HPMCOUNTER13H'),
        ('HPMCOUNTER14', 'HPMCOUNTER14H'),
        ('HPMCOUNTER15', 'HPMCOUNTER15H'),
        ('HPMCOUNTER16', 'HPMCOUNTER16H'),
        ('HPMCOUNTER17', 'HPMCOUNTER17H'),
        ('HPMCOUNTER18', 'HPMCOUNTER18H'),
        ('HPMCOUNTER19', 'HPMCOUNTER19H'),
        ('HPMCOUNTER20', 'HPMCOUNTER20H'),
        ('HPMCOUNTER21', 'HPMCOUNTER21H'),
        ('HPMCOUNTER22', 'HPMCOUNTER22H'),
        ('HPMCOUNTER23', 'HPMCOUNTER23H'),
        ('HPMCOUNTER24', 'HPMCOUNTER24H'),
        ('HPMCOUNTER25', 'HPMCOUNTER25H'),
        ('HPMCOUNTER26', 'HPMCOUNTER26H'),
        ('HPMCOUNTER27', 'HPMCOUNTER27H'),
        ('HPMCOUNTER28', 'HPMCOUNTER28H'),
        ('HPMCOUNTER29', 'HPMCOUNTER29H'),
        ('HPMCOUNTER30', 'HPMCOUNTER30H'),
        ('HPMCOUNTER31', 'HPMCOUNTER31H'),
        ('CYCLE', 'CYCLEH'),
        ('MINSTRET', 'MINSTRETH'),
        ('TIME', 'TIMEH'),
        ('MIE', 'SIE'),
        ('MIE', 'UIE'),
        ('MIP', 'SIP'),
        ('MIE', 'HIE'),
        ('MIP', 'HIP'),
        ('MIP', 'HVIP'),
        ('MIP', 'UIP'),
        ('VSSTATUS', 'SSTATUS'),
        ('VSTVAL', 'STVAL'),
        ('VSEPC', 'SEPC'),
        ('VSCAUSE', 'SCAUSE'),
        ('VSIP', 'SIP'),
        ('VSIE', 'SIE'),
        ('VSTVEC', 'STVEC'),
        ('VSSCRATCH', 'SSCRATCH'),
        ('VSATP', 'SATP'),
        ('MSTATUS', 'MSTATUSH'),
        ('HIP', 'HVIP'),
        ('HGEIP', 'HGEIE'),
        ('HIP', 'HGEIE')
        ]

same_groups_rv64 = [
        ('HIP', 'HVIP'),
        ('HGEIP', 'HGEIE'),
        ('HIP', 'HGEIE'),
        ('SSTATUS', 'MSTATUS'),
        ('USTATUS', 'MSTATUS'),
        ('MSTATUS', 'FCSR'),
        ('FRM', 'FCSR'),
        ('FFLAGS', 'FCSR'),
        ('MIE', 'SIE'),
        ('MIE', 'UIE'),
        ('MIP', 'SIP'),
        ('MIE', 'HIE'),
        ('MIP', 'HIP'),
        ('MIP', 'HVIP'),
        ('MIP', 'UIP'),
        ('VSSTATUS', 'SSTATUS'),
        ('VSTVAL', 'STVAL'),
        ('VSEPC', 'SEPC'),
        ('VSCAUSE', 'SCAUSE'),
        ('VSIP', 'SIP'),
        ('VSIE', 'SIE'),
        ('VSTVEC', 'STVEC'),
        ('VSSCRATCH', 'SSCRATCH'),
        ('VSATP', 'SATP'),
        ]

necessary_pairs_rv32 = [
        ('MSTATUS', 'MSTATUSH'),
        ('MHPMCOUNTER3', 'MHPMCOUNTER3H'),
        ('MHPMCOUNTER4', 'MHPMCOUNTER4H'),
        ('MHPMCOUNTER5', 'MHPMCOUNTER5H'),
        ('MHPMCOUNTER6', 'MHPMCOUNTER6H'),
        ('MHPMCOUNTER7', 'MHPMCOUNTER7H'),
        ('MHPMCOUNTER8', 'MHPMCOUNTER8H'),
        ('MHPMCOUNTER9', 'MHPMCOUNTER9H'),
        ('MHPMCOUNTER10', 'MHPMCOUNTER10H'),
        ('MHPMCOUNTER11', 'MHPMCOUNTER11H'),
        ('MHPMCOUNTER12', 'MHPMCOUNTER12H'),
        ('MHPMCOUNTER13', 'MHPMCOUNTER13H'),
        ('MHPMCOUNTER14', 'MHPMCOUNTER14H'),
        ('MHPMCOUNTER15', 'MHPMCOUNTER15H'),
        ('MHPMCOUNTER16', 'MHPMCOUNTER16H'),
        ('MHPMCOUNTER17', 'MHPMCOUNTER17H'),
        ('MHPMCOUNTER18', 'MHPMCOUNTER18H'),
        ('MHPMCOUNTER19', 'MHPMCOUNTER19H'),
        ('MHPMCOUNTER20', 'MHPMCOUNTER20H'),
        ('MHPMCOUNTER21', 'MHPMCOUNTER21H'),
        ('MHPMCOUNTER22', 'MHPMCOUNTER22H'),
        ('MHPMCOUNTER23', 'MHPMCOUNTER23H'),
        ('MHPMCOUNTER24', 'MHPMCOUNTER24H'),
        ('MHPMCOUNTER25', 'MHPMCOUNTER25H'),
        ('MHPMCOUNTER26', 'MHPMCOUNTER26H'),
        ('MHPMCOUNTER27', 'MHPMCOUNTER27H'),
        ('MHPMCOUNTER28', 'MHPMCOUNTER28H'),
        ('MHPMCOUNTER29', 'MHPMCOUNTER29H'),
        ('MHPMCOUNTER30', 'MHPMCOUNTER30H'),
        ('MHPMCOUNTER31', 'MHPMCOUNTER31H'),
        ('HPMCOUNTER3', 'HPMCOUNTER3H'),
        ('HPMCOUNTER4', 'HPMCOUNTER4H'),
        ('HPMCOUNTER5', 'HPMCOUNTER5H'),
        ('HPMCOUNTER6', 'HPMCOUNTER6H'),
        ('HPMCOUNTER7', 'HPMCOUNTER7H'),
        ('HPMCOUNTER8', 'HPMCOUNTER8H'),
        ('HPMCOUNTER9', 'HPMCOUNTER9H'),
        ('HPMCOUNTER10', 'HPMCOUNTER10H'),
        ('HPMCOUNTER11', 'HPMCOUNTER11H'),
        ('HPMCOUNTER12', 'HPMCOUNTER12H'),
        ('HPMCOUNTER13', 'HPMCOUNTER13H'),
        ('HPMCOUNTER14', 'HPMCOUNTER14H'),
        ('HPMCOUNTER15', 'HPMCOUNTER15H'),
        ('HPMCOUNTER16', 'HPMCOUNTER16H'),
        ('HPMCOUNTER17', 'HPMCOUNTER17H'),
        ('HPMCOUNTER18', 'HPMCOUNTER18H'),
        ('HPMCOUNTER19', 'HPMCOUNTER19H'),
        ('HPMCOUNTER20', 'HPMCOUNTER20H'),
        ('HPMCOUNTER21', 'HPMCOUNTER21H'),
        ('HPMCOUNTER22', 'HPMCOUNTER22H'),
        ('HPMCOUNTER23', 'HPMCOUNTER23H'),
        ('HPMCOUNTER24', 'HPMCOUNTER24H'),
        ('HPMCOUNTER25', 'HPMCOUNTER25H'),
        ('HPMCOUNTER26', 'HPMCOUNTER26H'),
        ('HPMCOUNTER27', 'HPMCOUNTER27H'),
        ('HPMCOUNTER28', 'HPMCOUNTER28H'),
        ('HPMCOUNTER29', 'HPMCOUNTER29H'),
        ('HPMCOUNTER30', 'HPMCOUNTER30H'),
        ('HPMCOUNTER31', 'HPMCOUNTER31H'),
        ('CYCLE', 'CYCLEH'),
        ('MINSTRET', 'MINSTRETH'),
        ('TIME', 'TIMEH')
        ]
