#BEGIN_LEGAL
#
#Copyright (c) 2017 Intel Corporation
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.
#  
#END_LEGAL
from __future__ import print_function
import sys
import os
import codegen
import encutil
import genutil
import actions
import verbosity

max_in_byte = 256 #max unsigned int per byte
emit_function_prefix = 'xed_encode_instruction_emit_pattern'
bind_function_prefix = 'xed_encode_instruction_fb_pattern'
get_field_value = 'xed_encoder_get_start_field_value'
legacy_maps = {'map0':'XED_ILD_MAP0',
               'map1':'XED_ILD_MAP1',
               'map2':'XED_ILD_MAP2',
               'map3':'XED_ILD_MAP3',
               '3dnow':'XED_ILD_MAPAMD' } 


def key_field_binding_lower(x):
    return x.field_name.lower()
    
def sort_field_bindings(a,b):
    ''' sort action_t of type emit '''
    
    if a.field_name.lower() > b.field_name.lower():
        return 1
    elif a.field_name.lower() < b.field_name.lower():
        return -1
    return 0

def key_iform_by_bind_ptrn(x):
    return x.bind_ptrn

def cmp_iforms_by_bind_ptrn(a,b):  # FIXME:2017-06-10: PY3 port, no longer used
    if a.bind_ptrn > b.bind_ptrn:
        return 1
    elif a.bind_ptrn < b.bind_ptrn:
        return -1
    return 0

def key_priority(x):
    return x.priority
def key_rule_length(x):
    return len(x.rule.get_all_emits() + x.rule.get_all_nts())

def cmp_iform_len(a,b): # FIXME:2017-06-10: PY3 port, no longer used
    if a.priority >  b.priority:
        return 1
    elif a.priority <  b.priority:
        return -1

    alen = len(a.rule.get_all_emits() + a.rule.get_all_nts())
    blen = len(b.rule.get_all_emits() + b.rule.get_all_nts())
    if alen > blen:
        return 1
    elif alen < blen:
        return -1
    return cmp_iforms_by_bind_ptrn(a,b)


class instructions_group_t(object):
    ''' each encoding iform has:
        1. conditions ( e.g.REG1=GPRv_r() )
        2. actions, one type of the actions is a nonterminal (nt)
        
        the conditions and the nt's are called "bind patterns".
          
        if two different iclasses have the same bind patterns
        for all of their iforms,
        we can put those iclasses in the same group.
        
        this is what we are doing in _join_iclasses_to_groups 
        '''
    
    def __init__(self,iarray,log_dir):
        self.groups = []
        self.iclass2group = {}
        self.log_name = 'groups_log.txt'
        self._join_iclasses_to_groups(iarray,log_dir)
        
    def _group_good_for_iclass(self,group,iforms):
        ''' Check if the incoming group represents the list of iforms.
        A group represents a list of iforms if:
        1. it has same number of iforms.
        2. for each iform there is an iform in the group that has the same 
           bind pattern
        
        @param group: ins_group_t object
        @param iforms: a list of iform_t 
        
        @return: True if group represents the the ifoms list '''
        
        if len(group.iforms) != len(iforms):
            return False
        for iform,group_iform in zip(iforms,group.iforms):
            if iform.bind_ptrn != group_iform.bind_ptrn:
                return False
        
        return True
            
    def _put_iclass_in_group(self,groups,iclass,instruction_iforms):
        ''' tries to find a group that represents the incoming iclass.
            'represents' means that all the iforms have exactly the same
            bind patterns.
            if no group was found, then create new group for the iclass. 
            
            @param groups: a list of ins_group_t object 
            @param iclass: the iclass name
            @param instruction_iforms: a list of iform_t, the 
                                       iforms of the iclass 
            
            @return: function_object_t '''
        
        for group in groups:
            # check if group represents the iclass
            if self._group_good_for_iclass(group,instruction_iforms):
                group.add_iclass(iclass,instruction_iforms)
                return
        
        #no matching groups
        #create new one 
        group = ins_group_t()
        group.add_iclass(iclass,instruction_iforms)
        groups.append(group)
        return
                 
    def _join_iclasses_to_groups(self,iarray,log_dir):
        '''           
            1. dividing the iclasses into groups.
            2. creating a mapping from iclass to its group Id.
            3. generating a log
            
            return: a list of ins_group_t objects '''
        
        
        groups = []
        #1. generate the groups
        for iclass,iforms in list(iarray.items()):
            iforms.sort(key=key_iform_by_bind_ptrn)
            self._put_iclass_in_group(groups,iclass,iforms)
        
        # 2. generate the iclass to group Id mapping
        self.iclass2group = {}
        for i,group in enumerate(groups):
            for iclass in group.get_iclasses():
                self.iclass2group[iclass] = i
        
        # 3. print the log
        if verbosity.vencode():
            log_file = os.path.join(log_dir,self.log_name) 
            df = open(log_file,'w') #debug file
            df.write("number of iclasses: %d\n" % len(iarray))
            df.write("number of groups: %d\n" % len(groups))
            for i,group in enumerate(groups):
                df.write("GROUP Id: %d\n" % i)
                df.write("ICLASSES: %s\n" % str(group.get_iclasses()))
                for iform in group.iforms:
                    df.write("%s: %s\n" % ('BIND PATTERN: ', iform.bind_ptrn ))
                df.write("\n\n")

            df.close()     
        self.groups = groups
    
    def get_groups(self):
        ''' return the groups list ''' 
        return self.groups
    
    def num_groups(self):
        ''' return the number of groups ''' 
        return len(self.groups)
    
    def get_iclass2group(self):
        ''' return a dic of iclass to it group Id'''
        return self.iclass2group
        
    def get_iclass2index_in_group(self):
        ''' return a dictionary of iclass to its index in the group'''
        d = {}
        for group in self.groups:
            iclasses = sorted(group.get_iclasses())
            for i,iclass in enumerate(iclasses):
                d[iclass] = i
        
        return d
        
class ins_group_t(object):
    ''' This class represents one group.
        it holds the list of iclasses that have the same bind patterns.   
    '''
    
    def __init__(self):
        ''' params:
            1. iclass2iforms: mapping from iclass to a list of iforms
            2.iforms: list of iform_t objects  
        '''
        
        self.iclass2iforms = {}
        self.iforms = []
        
    def add_iclass(self,iclass,iforms):
        ''' add the iclass and iforms list to the group '''
        
        self.iclass2iforms[iclass] = iforms
        if not self.iforms:
            self.iforms = iforms
        
    def get_iclasses(self):
        ''' return a list of iclasses in the group'''
        return list(self.iclass2iforms.keys())     
    
    def get_iform_ids_table(self):
        ''' generate C style table of iform Id's.
            the table is 2D. one row per iclass.
            the columns are the different iform Ids '''
        
        table = []
        iclasses = sorted(self.get_iclasses())
        for iclass in iclasses:
            values = ''
            iforms_sorted_by_length = self.iclass2iforms[iclass]

            iforms_sorted_by_length.sort(key=key_iform_by_bind_ptrn)
            iforms_sorted_by_length.sort(key=key_rule_length)
            iforms_sorted_by_length.sort(key=key_priority)
            
            for iform in iforms_sorted_by_length:
                values += '%4d,' % iform.rule.iform_id
            line = "/*%10s*/    {%s}," % (iclass,values)
            table.extend([ line ])
            
        return table


class instruction_codegen_t():
    def __init__(self,iform_list,iarray,logs_dir, amd_enabled=True):
        self.amd_enabled = amd_enabled
        self.iform_list = iform_list
        self.iarray = iarray
        self.logs_dir = logs_dir #directory for the log file
        
        #list of field binding function_object_t
        self.fb_ptrs_fo_list = None
        #list of emit patterns function_object_t
        self.emit_ptrs_fo_list = None
        
        # number of field binding patterns
        self.max_fb_ptrns = None
        # number of emit patterns
        self.max_emit_ptrns = None
        
        # a list of all values been set to field ordered sequentially 
        self.fb_values_list = None
        # the length of fb_values_list 
        self.fb_values_table_size = None
        
        # list of groups (instructions_group_t) 
        self.instruction_groups = None
        
    def get_values(self,encoder_config):
        ''' copy the necessary fields to encoder_confing object  '''
            
        encoder_config.fb_values_list = self.fb_values_list
        encoder_config.fb_values_table_size = self.fb_values_table_size
        
        encoder_config.emit_ptrs_fo_list = self.emit_ptrs_fo_list
        encoder_config.max_emit_ptrns = self.max_emit_ptrns
      
        encoder_config.fb_ptrs_fo_list = self.fb_ptrs_fo_list
        encoder_config.max_fb_ptrns = self.max_fb_ptrns
        
        encoder_config.ins_groups = self.instruction_groups
        
         
    def _make_emit_fo(self, iform, i):
        ''' create the function object for this emit pattern
             
            @param iform: iform_t object
            @param i: index of the pattern function
            @return: function_object_t 
        '''
        
        fname = "%s_%d" % (emit_function_prefix,i)
        fo = codegen.function_object_t(fname,
                                       return_type='void')
        
        # obj_str is the function parameters for the emit function
        obj_str = encutil.enc_strings['obj_str']
        enc_arg = "%s* %s" % (encutil.enc_strings['obj_type'],
                              obj_str)
        fo.add_arg(enc_arg)
      
        for action in iform.rule.actions:
            if action.field_name and action.field_name == 'MAP':
                    emit_map = 'xed_encoder_request_emit_legacy_map'
                    code = "    %s(%s)" % (emit_map,obj_str)
                    fo.add_code_eol(code)
                    
            elif action.field_name and action.field_name == 'NOM_OPCODE':
                code = ''
                get_opcode = 'xed_encoder_get_nominal_opcode(%s)' % obj_str
                if action.nbits == 8:
                    emit_func = 'xed_encoder_request_emit_bytes'
                else:
                    emit_func = 'xed_encoder_request_encode_emit'
                code = ' '*4
                code += '%s(%s,%d,%s)' % (emit_func,obj_str,
                                          action.nbits,get_opcode) 
                fo.add_code_eol(code)     
            else:
                code = action.emit_code('EMIT')
                for c in code:
                    fo.add_code(c)
        
        return fo     
    
    def _make_fb_setter_fo(self, iform, i):
        ''' create the function object for pattern of fields bindings 
             
            @param iform: iform_t object 
            @param i: index of the pattern function
            @return: function_object_t 
        '''
        
        fname = "%s_%d" % (bind_function_prefix,i)
        fo = codegen.function_object_t(fname,
                                       return_type='void')
        
        obj_name = encutil.enc_strings['obj_str']
        enc_arg = "%s* %s" % (encutil.enc_strings['obj_type'],
                              obj_name)
        fo.add_arg(enc_arg)
        
        if not iform.fbs:
            #no field binding we need to set, pacify the compiler
            fo.add_code_eol('(void)%s' % obj_name)
            return fo
        
        fo.add_code_eol('    const xed_uint8_t* val')
        fo.add_code_eol('    val = %s(%s)' % (get_field_value, obj_name))
        for i,fb_action in enumerate(iform.fbs):
            value_from_lu_table = '*(val+%d)' % i
            operand_setter = "%s_set_%s" % (encutil.enc_strings['op_accessor'],
                                                fb_action.field_name.lower())
            code = '    %s(%s,%s);' % (operand_setter,
                                obj_name, value_from_lu_table)
            fo.add_code(code)
    
        return fo     
    
    def _verify_naked_bits_in_unique_pattern(self):
        ''' calculate how many references we have per each full
            instruction emit pattern.
        
            naked bits are bits in the pattern without a field name
            like 0x0F or 0b110.  earlier functions decorated
            opcode/legacy map.  

            If the naked bits just show up once, then we can hardcode
            those bits in the emit function. This is a test for that.

            Current design relies on the naked bits being the same in
            similar instruction patterns. If two patterns differ in
            any naked bits, they cannot share emit functions and we die.
            The workaround would be to capture the bits in some field to
            allow the emit function to be shared & generic.

            The current inputs to XED have no such conflicts.
        '''
        refs_per_ptrn ={}
        for iform in self.iform_list:
            if iform.emit_actions not in refs_per_ptrn: 
                refs_per_ptrn[iform.emit_actions] = 1
            else:
                refs_per_ptrn[iform.emit_actions] += 1
                if iform.rule.has_naked_bit_action():
                    err = 'emit pattern: %s has more than one reference ' +\
                          'use of naked bits is not allowed'%iform.emit_actions 
                    genutil.die(err)
    
    def _make_emit_pattern_fos(self):
        ''' collect all the different patterns for emit phase.
            for each pattern create a function representing it.
            adds to each rule in iform_t the index of the pattern function
             
            @return: list of emit pattern function name to function object 
        '''
        emit_patterns = {}
        fo_list = []
        i = 0
        
        for iform in self.iform_list:
            if iform.emit_actions not in emit_patterns: 
                fo = self._make_emit_fo(iform,i)
                emit_patterns[iform.emit_actions] = (fo,i)
                fo_list.append(fo)
                iform.emit_func_index = i
                i += 1 
            
            else:
                fo, index = emit_patterns[iform.emit_actions]
                iform.emit_func_index = index 
    
        return fo_list
    
    
    def _make_fb_pattern_fos(self):
        ''' collect all the different patterns for bind phase.
            for each pattern create a function representing it.
            adds to each rule in iform_t the index of the pattern function
             
            @return: list of emit pattern function name to function object 
        '''
        bind_ptterns = {}
        fo_list = []
        i = 0
        
        for iform in self.iform_list:
            if iform.fb_ptrn not in bind_ptterns: 
                fo = self._make_fb_setter_fo(iform,i)
                bind_ptterns[iform.fb_ptrn] = (fo,i)
                fo_list.append(fo)
                iform.bind_func_index = i
                i += 1 
            
            else:
                fo,index = bind_ptterns[iform.fb_ptrn]
                iform.bind_func_index = index 
    
        return fo_list
    
    def _identify_map_and_nominal_opcode(self,iform):
        ''' scan the list of actions and identify the nominal opcode and 
            the legacy map.
            replace the actions that describe the bytes of the nom opcode 
            and map with dummy action as place holders. 
        '''
        
        #list of all prefixes
        prefixes = [0x66,0x67,0xf2,0xf3,0xf0,0x64,0x65,0x2e,0x3e,0x26,0x36]
        vv = 0
        first_naked_bits_index = None
        for i,action in enumerate(iform.rule.actions):
            if action.is_field_binding() and action.field_name == 'VEXVALID':
                # we are in vex valid 1/2/3
                vv = 1 
            if action.naked_bits():
                if vv == 0 and action.int_value in prefixes:
                    #we are in legacy space and this byte is 
                    #a prefix, don't care
                    continue
                else:
                    #this byte represents the nominal opcode or the legacy map
                    first_naked_bits_index = i
                    break
        
        if first_naked_bits_index == None:
            err = "did not find nominal opcode for iform: %s" % str(iform)
            genutil.die(err)
    
        last_index = len(iform.rule.actions) - 1
        
        first =  iform.rule.actions[first_naked_bits_index]
        if first.int_value != 0x0F or vv:
            #this action represents the opcode
            iform.nominal_opcode = first.int_value
            iform.nom_opcode_bits = first.nbits
            # FIXME: mjc: 2017-05-19: this ultimately gets dumped in
            # to the xed-encoder-iforms-init.c file and all the
            # VEX/EVEX/XOP encoded stuff are listed as XED_ILD_MAP0
            # which is wrong.  This is only used for encoding the legacy maps.
            # The actual map comes from the field-bindings collected later
            iform.map = legacy_maps['map0'] # legacy only, Not all vexvalid instr are map0.
            #replacing with place holder
            iform.rule.actions[i] = actions.dummy_emit(first,'NOM_OPCODE')
        
        else: #first byte == 0x0F and we are legacy space
            #check that we have at least one more byte to read
            if first_naked_bits_index+1 > last_index:
                    genutil.die("not enough actions")
            
            second = iform.rule.actions[first_naked_bits_index+1]
            if not second.naked_bits():
                genutil.die("expecting map/nominal opcode after 0x0F byte")
            
            if self.amd_enabled and second.int_value == 0x0F: #3DNow
                # the nominal opcode in 3DNow is in the last action.
                # FIXME: it is best to not reference directly the last action
                #        but rather add a meaningful field name to the action 
                amd3dnow_opcode_action = iform.rule.actions[-1]
                iform.nominal_opcode = amd3dnow_opcode_action.int_value
                iform.nom_opcode_bits = 8
                iform.map = legacy_maps['3dnow']
                iform.rule.actions[-1] = actions.dummy_emit(
                                           amd3dnow_opcode_action,'NOM_OPCODE')
                iform.rule.actions[i] = actions.dummy_emit(first,'MAP')
                #the second byte that describes the map 
                #is not needed, remove it
                iform.rule.actions.remove(second)
                
            elif second.int_value == 0x38 or second.int_value == 0x3A:
                #check that we have at least one more byte to read
                if first_naked_bits_index+2 > last_index:
                    genutil.die("not enough actions")
                
                third = iform.rule.actions[first_naked_bits_index+2]
                if not third.naked_bits():
                    genutil.die("expecting map/nominal opcode after 0x0F byte")
                
                iform.nominal_opcode = third.int_value
                iform.nom_opcode_bits = third.nbits
                
                if second.int_value == 0x38:
                    iform.map = legacy_maps['map2']
                else: #0x3A
                    iform.map = legacy_maps['map3']
                iform.rule.actions[i+1] = actions.dummy_emit(second,'MAP')
                iform.rule.actions[i+2] = actions.dummy_emit(third,
                                                             'NOM_OPCODE')  
                iform.rule.actions.remove(first)
                
            else:
                iform.nominal_opcode = second.int_value 
                iform.nom_opcode_bits = second.nbits
                iform.map = legacy_maps['map1']
                iform.rule.actions[i] = actions.dummy_emit(first,'MAP')
                iform.rule.actions[i+1] = actions.dummy_emit(second,
                                                             'NOM_OPCODE')
        
    def _find_sub_list(self,all_fbs_values, fbs_values):
        ''' find the the sub list: fbs_values
            in the list: all_fbs_values.
            
            if not found return -1
            if found return the fist index of the recurrence '''
            
        elems = len(fbs_values)
        indices_to_scan =  len(all_fbs_values) - elems + 1
        for i in range(indices_to_scan):
            if fbs_values == all_fbs_values[i:i+elems]:
                return i
        return -1
        
    
    def _find_fb_occurrence(self,all_fbs_values, fbs_values):
        ''' find the the sub list: fbs_values
            in the list: all_fbs_values.
            
            if fbs_values is not a sub list to all_fbs_values
            concatenate it.
            
            return: the first index of fbs_values occurrence 
                    in all_fbs_values.  
        '''
        
        if not fbs_values:
            return 0
        
        if not all_fbs_values:
            all_fbs_values.extend(fbs_values)
            return  0
        
        index = self._find_sub_list(all_fbs_values,fbs_values)
        if index >= 0:
            # found sub list
            return index
        
        # did not found sub list concatenate to the end
        last_index = len(all_fbs_values)
        all_fbs_values.extend(fbs_values)
        return last_index 
        
    
    def _make_fb_values_list(self):
        ''' generate a list of the values being set by the FB actions.
            for each iform find the start index of the values list. 

            All the field bindings get put in to a linear array.
            This is finds the index in to that array. 

            This is a quick compression technique for sharing trailing
            subsequences. 
            
            e.g.: iform1 sets the values: 0 1 2  (3 fields)
                  iform2 sets the values: 3 4    (2 fields)
                  iform3 sets the values: 1 2    
                  iform4 sets the values: 2 3
                  
                  the ordered list of unique sequence values across
                  all iforms is: 0 1 2 3 4.
                                           
                  start index of iform1: 0  (which picks up 0, 1 2)       
                  start index of iform2: 3  (which picks up 3, 4)
                  start index of iform3: 1  (which picks up 1, 2)
                  start index of iform4: 2  (which picks up 2, 3)

                  Note: because of ordering, if iform3 happens to show
                  up before iform1, they won't share iform1's
                  subsequence 1,2.
            '''
        
        fbs_list = []
        for iform in self.iform_list:
            # collect all the actions that set fields
            iform.fbs = iform.rule.get_all_fbs() 
            iform.fbs.sort(key=key_field_binding_lower) 
            
            # create a list of int values
            fbs_values = [ x.int_value for x in iform.fbs]
            
            #find the start index of this list of values in the general list
            #and update the general list as needed  
            iform.fb_index = self._find_fb_occurrence(fbs_list, fbs_values)
                
        fbs_list = [ str(x) for x in fbs_list]
        return fbs_list
            
            
    def _make_field_bindings_pattern(self,iform):
        ''' create the string that represents the field bindings pattern. '''
            
        bind_actions = []
        for action in iform.rule.actions:
            if action.type == 'nt':
                pass
            elif action.type == 'FB':
                bind_actions.append(action.field_name)
            elif action.type == 'emit':
                if action.emit_type == 'numeric' and action.field_name:
                    bind_actions.append(action.field_name)
                else:
                    pass
            else:
                genutil.die("unexpected action type: %s" % action.type)    
                                  
        fb_ptrn =  ''
        if bind_actions:
            fb_ptrn = ', '.join(sorted(bind_actions))
        iform.fb_ptrn = fb_ptrn

    def _make_emit_pattern(self,iform):
        ''' create the string that represents the action for the emit phase.
            using this string we will classify all 
            the emit actions into patterns 
            '''
        
        emit_pattern = []
        
        for action in iform.rule.actions:
            if action.type == 'emit':
                emit_pattern.append("emit %s nbits=%d" % (action.field_name,
                                                          action.nbits))
            elif action.type == 'nt':
                emit_pattern.append(str(action))
            elif action.type == 'FB':
                # FB are not used in emit phase so we do not factor them 
                # in to the string that represents the pattern
                pass
            else:
                genutil.die("unexpected action type: %s" % action.type)    

        iform.emit_actions = ', '.join(emit_pattern)
    
    def _make_bind_pattern(self,iform):
        ''' create the string that represents the field bindings pattern. '''
            
        bind_ptrn = [ str(iform.rule.conditions) ]
        for action in iform.rule.actions:
            if action.type == 'nt':
                bind_ptrn.append(str(action))
                                  
        iform.bind_ptrn =  ''
        if bind_ptrn:
            iform.bind_ptrn = ', '.join(bind_ptrn)
              
    def _print_log(self):
        print("---- encoder log ----")
        for i,iform in enumerate(self.iform_list):
            print("%d\n" % i)
            print("IFORM: %s" % str(iform))
            print("iform index: %d" % iform.rule.iform_id)
            bind_index = iform.bind_func_index
            bind_fo = self.fb_ptrs_fo_list[bind_index]
            print("BIND function: %d, %s" % (bind_index,
                                             bind_fo.function_name))
            emit_index = iform.emit_func_index
            emit_fo = self.emit_ptrs_fo_list[emit_index]
            print("EMIT function: %d, %s" % (emit_index,
                                             emit_fo.function_name))
            
            print("NOM_OPCODE: %d" % iform.nominal_opcode)
            print("MAP: %s" % iform.map)
            fbs_values = [ x.int_value for x in iform.fbs]
            print("FB values: %s" % fbs_values)
            print("\n\n")
            print("-"*20) 
    
    def work(self):  # main entry point
        ''' 
            Each instruction has 
                1) conditions (iclass, user registers, user inputs) and 

                2) actions. 3 types:
                   2a) field bindings, 
                   2b) nonterminals, 
                   2c) bit-emit of operand fields 
                          (hard-coded or from NT output)).

              fos = function output object (plural)

            generate the following:
            1) list of emit patterns fos  (2c)
            2) list of field bindings patterns fos (2a)
            3) list of all field bindings values  (values from prev step)
            4) max number of emit patterns  
            5) max number of field binding patterns
            6) max number of field bindings values
            7) list of groups fos (see explanation in instructions_group_t)
            
        '''
        
        for iform in self.iform_list:
            self._identify_map_and_nominal_opcode(iform)
            self._make_field_bindings_pattern(iform)
            self._make_emit_pattern(iform)
            #see explanation about bind patterns in instructions_group_t
            self._make_bind_pattern(iform)  
        
        self._verify_naked_bits_in_unique_pattern()
        
        self.fb_values_list = self._make_fb_values_list() # step 3
        self.fb_values_table_size = len(self.fb_values_list)
        
        self.emit_ptrs_fo_list = self._make_emit_pattern_fos()
        self.max_emit_ptrns = len(self.emit_ptrs_fo_list)
        if self.max_emit_ptrns > max_in_byte:
            # we are using uint8to hold the number of patterns,
            # we need to make sure we don't exceeds 
            error = "total number of emit patterns(%d) exceeds 8 bits"
            genutil.die(error % self.max_emit_ptrns)
            
        self.instruction_groups = instructions_group_t(self.iarray,
                                                       self.logs_dir)
        
        self.fb_ptrs_fo_list = self._make_fb_pattern_fos()
        self.max_fb_ptrns = len(self.fb_ptrs_fo_list)
        if self.max_fb_ptrns > max_in_byte:
            # we are using uint8to hold the number of patterns,
            # we need to make sure we don't exceeds
            error = "total number of field binding patterns(%d) exceeds 8 bits"
            genutil.die(error % self.max_fb_ptrns)

        if verbosity.vencode():
            self._print_log()   
    
    
    

        
        
        
        
        
            
            
        
        
               
