
import sys
import utilities as util

class wbslave:
    
    def __init__(self, carrier, baseaddr, addrtable ):
        self.carrier = carrier;
        self.baseaddr = baseaddr;
        self.addrtable = addrtable;
    
          

    def read_reg_mask(self, address, mask ):
        tmp = self.carrier.read(address + self.baseaddr);
        return self.read_mask(tmp, mask) ;
        
        
    def write_reg_mask(self, address, mask, value ):
        tmp = self.carrier.read(address + self.baseaddr );
        tmp = self.modify_mask( tmp, mask, value );
        self.carrier.write(address + self.baseaddr, tmp);
        return True
        
        
    def write_regname(self, name, value ):
        reginfo = self.get_addr(name);
        if not self.iscorrect(reginfo):
            util.dbg_msg( "Register not found" )
            return False
        if not self.iswritable(reginfo[2]):
            util.dbg_msg( "Register is not writeable" )
            return False
        
        self.write_reg_mask(4*reginfo[0], reginfo[1], value)
            
    def read_regname(self, name ):
        reginfo = self.get_addr(name);
        if not self.iscorrect(reginfo):
            util.dbg_msg( "Register not found" )
            return -1
        if not self.isreadable(reginfo[2]):
            util.dbg_msg( "Register is not readable" )
            return -1
        
        return self.read_reg_mask(4*reginfo[0], reginfo[1])
        
        
    
    
    ###########################################################################
    ################### helper methods ########################################
    ###########################################################################

    def iscorrect(self, reginfo ):
        if not isinstance(reginfo, list):
            util.dbg_msg( "Reginfo is not a list" )
            return False
            
        else:
            if len( reginfo ) != 3 :
                util.dbg_msg( "Reginfo length is different then 3" )
                return False
            else:
                return True
    
    def iswritable(self, permission ):
        if ( permission == "rw" ) or ( permission == "w" ):
            return True
        else:
            return False
    
    def isreadable(self, permission ):     
        if ( permission == "rw" ) or ( permission == "r" ):
            return True
        else:
            return False
    
    def check_consecutive( self, mask ):
        size = sys.getsizeof(mask);
        curr = 0;
        for i in range(size):
            
            if curr == 0:
                if mask & ( 1 << i ) :
                    curr = 1;
            
            elif curr == 1:
                if not ( mask & ( 1 << i ) ) :
                    curr = 2;
            elif curr == 2:
                if mask & ( 1 << i ) :
                    return False
        
        return True
                
    
    
    def read_mask( self, value, mask ):
    #     clear all unmasked bits
        value = value & mask;
        bit = 1;
    #     right shift the value until it starts from bit 0
        while ( not (mask & bit) ): 
            bit = bit << 1;
            value = value >> 1;
        return value;
        
        
    
    
    def modify_mask( self, previous, mask, new ):
        bit = 1;
    #     shift new value to align with mask
        while ( not (mask & bit) ): 
            bit = bit << 1;
            new = new << 1;
    #     make sure that new value doesn't exceed mask
        new = new & mask;
    #     clear masked bits in previous value
        previous = previous & (~mask);
    #     bit-or previous and new values
        new = new | previous;
        return new;
    
    
    def get_addr( self, name ):
        try :
            tmp = self.addrtable[name];
        except KeyError:
            return 0
        
        return tmp;