This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

A TivaWare weakness (and a simple addition to address it)



I've been working on extracting field information for DID0 and 1 and quickly realized there was something missing in the TivaWare macros. Although the fields in the registers had masks defined they did not have position (shift) information defined which makes reporting in a friendly readable fashion difficult. I first added shifts manually but that's going to be a maintenance headache and irked me since the needed information is actually embedded in the mask. You could use a function to calculate the position with relative shifts but that seemed an inelegant waste. So I did a little searching and noodling.  The core of this (the position calc) comes from others but I've not seen quite this form, they were interested in the reverse problem.

First the macros to implement the solution. The macro that would be used is GET_SUB_FIELD which returns the value of the field given an integer and a mask.

#ifdef __cplusplus
extern "C" {
#endif 

	/* Macros used to extract a subfield given only the mask. Needed since 
	   TivaWare defines the mask but not the offset, so the offset must be 
	   calculated.
	   
	   SUB_FIELD_DIVISOR calulates a divisor to shift the field right. This 
	   works by overlapping the mask for 1 bit by sifting the inverse of the 
	   mask left by 1. This will give a power of two divide. 
	   	IMPORTANT NOTE: This only works if the mask is contiguous, gaps 
		   in the mask will cause errors
	   	IMPORTANT NOTE: Argument is evaluated multiple times 
	
	   GET_SUB_FIELD returns a sub field of an integer type field given a 
	   mask for that field. The mask must consist of a sequential set of 
	   bits set that indicate the bits containing the sub field.  This field 
	   is shifted right to align its rightmost bit on bit 0. Since the 
	   divisor will be a power of 2, when a constant for themask is used 
	   then the compiler is free to replace the divide by a shift.  
	   	IMPORTANT NOTE: Argument mask is evaluated multiple times */
#define SUB_FIELD_DIVISOR(mask)((mask) & ~((mask) << 1))
#define GET_SUB_FIELD(val,mask) (((val) & (mask))/SUB_FIELD_DIVISOR((mask)))

#ifdef __cplusplus
}
#endif 

Next the tests

TEST(subfield_test, mask_offset_0) {

    RESET_FFF();
    
    	// Check no mask case.  This is actually an error but it's not detected 
	//  by the code. We will rely on lint to catch.
    EXPECT_EQ(0u,SUB_FIELD_DIVISOR(0u));
}

TEST(subfield_test, mask_offset_1) {

    RESET_FFF();
    
    	// Check simple 1 bit field with no offset.  Should produce a divider of 1 
    EXPECT_EQ(1u,SUB_FIELD_DIVISOR(1u));
}

TEST(subfield_test, mask_offset_1x) {

    RESET_FFF();
    
    	// Check simple multiple bit field with no offset.  Should produce a divider of 1 
    EXPECT_EQ(1u,SUB_FIELD_DIVISOR(3u));
    EXPECT_EQ(1u,SUB_FIELD_DIVISOR(0xFu));
    EXPECT_EQ(1u,SUB_FIELD_DIVISOR(0xFFu));
}

TEST(subfield_test, mask_offset_3) {

    RESET_FFF();
    
    	// Check simple 1 bit field with a 3 bit offset.  Should produce a divider of 8 
    EXPECT_EQ(8u,SUB_FIELD_DIVISOR(0x8u));
}

TEST(subfield_test, mask_offset_3x) {

    RESET_FFF();
    
    	// Check simple multiple bit field 3 bit offset.  Should produce a divider of 8 
    EXPECT_EQ(8u,SUB_FIELD_DIVISOR(0x18u));
    EXPECT_EQ(8u,SUB_FIELD_DIVISOR(0xF8u));
    EXPECT_EQ(8u,SUB_FIELD_DIVISOR(0xFF8u));
}

TEST(subfield_test, mask_offset_8) {

    RESET_FFF();
    
    	// Check simple 1 bit field with a 8 bit offset.  Should produce a divider of 256 
    EXPECT_EQ(256u,SUB_FIELD_DIVISOR(0x100u));
}

TEST(subfield_test, mask_offset_8x) {

    RESET_FFF();
    
    	// Check simple multiple bit field with a 8 bit offset.  Should produce a divider of 256 
    EXPECT_EQ(256u,SUB_FIELD_DIVISOR(0x300u));
    EXPECT_EQ(256u,SUB_FIELD_DIVISOR(0xF00u));
    EXPECT_EQ(256u,SUB_FIELD_DIVISOR(0xFF00u));
}

TEST(subfield_test, get_subfield_1) {

    RESET_FFF();
    
    	// extract a simple one bit field at different offsets with no other 
	// bits set 
    EXPECT_EQ(1u,GET_SUB_FIELD(0x1u, 0x1u));
    EXPECT_EQ(0u,GET_SUB_FIELD(0x0u, 0x1u));
    EXPECT_EQ(1u,GET_SUB_FIELD(0x10u, 0x10u));
    EXPECT_EQ(0u,GET_SUB_FIELD(0x0u, 0x10u));
    EXPECT_EQ(1u,GET_SUB_FIELD(0x100u, 0x100u));
    EXPECT_EQ(0u,GET_SUB_FIELD(0x0u, 0x100u));
}

TEST(subfield_test, get_subfield_1x) {

    RESET_FFF();
    
    	// extract a simple one bit field with other bits set. 
    EXPECT_EQ(1u,GET_SUB_FIELD(0x1Fu, 0x10u));
    EXPECT_EQ(0u,GET_SUB_FIELD(0x0Fu, 0x10u));
    EXPECT_EQ(1u,GET_SUB_FIELD(0xF0u, 0x10u));
    EXPECT_EQ(0u,GET_SUB_FIELD(0xE0u, 0x10u));
    EXPECT_EQ(1u,GET_SUB_FIELD(0xFFu, 0x10u));
    EXPECT_EQ(0u,GET_SUB_FIELD(0xEFu, 0x10u));
}

TEST(subfield_test, get_subfield_4x) {

    RESET_FFF();
    
    	// extract a multiple bit field. 
    EXPECT_EQ(1u,GET_SUB_FIELD(0x1Fu, 0xF0u));
    EXPECT_EQ(0u,GET_SUB_FIELD(0x0Fu, 0xF0u));
    EXPECT_EQ(1u,GET_SUB_FIELD(0xF10u, 0xF0u));
    EXPECT_EQ(0xFu,GET_SUB_FIELD(0xFF0u, 0xF0u));
    EXPECT_EQ(0x2u,GET_SUB_FIELD(0x2Fu, 0xF0u));
    EXPECT_EQ(0x5u,GET_SUB_FIELD(0x5Fu, 0xF0u));
    EXPECT_EQ(0x3u,GET_SUB_FIELD(0xF30u, 0xF0u));
    EXPECT_EQ(0x7u,GET_SUB_FIELD(0xF70u, 0xF0u));
    EXPECT_EQ(0xAu,GET_SUB_FIELD(0xFAFu, 0xF0u));
    EXPECT_EQ(0xCu,GET_SUB_FIELD(0xFCCu, 0xF0u));
}

I use google test but I haven't included any of the framework needed (includes etc..) The tests already proved valuable, detecting simple oversights.

Robert

  • Hello Robert,

    Actually, there are some register bit masks that have positions defined and some that do not.

    Regards
    Amit
  • I'm not sure if that's better or not Amit. The weakness still needs addressing. There is one advantage to using the macro. It only requires that the information be entered once. That's negated if the headers are automatically generated. In which case the question probably should be why are offsets not automatically generated every time a mask is.

    In any case, I found an error when dealing with sub fields at the high end of the integer.  A left shift of a set 32'nd bit is undefined. So corrected macros and tests

    	/* Macros used to extract a subfield given only the mask. Needed since 
    	   TivaWare defines the mask but not the offset, so the offset must be 
    	   calculated.
    	   
    	   SUB_FIELD_DIVISOR calulates a divisor to shift the field right. This 
    	   works by overlapping the mask for 1 bit by sifting the inverse of the 
    	   mask left by 1. This will give a power of two divide. 
    	   	IMPORTANT NOTE: This only works if the mask is contiguous, gaps 
    		   in the mask will cause errors
    	   	IMPORTANT NOTE: Argument is evaluated multiple times 
    	
    	   GET_SUB_FIELD returns a sub field of an integer type field given a 
    	   mask for that field. The mask must consist of a sequential set of 
    	   bits set that indicate the bits containing the sub field.  This field 
    	   is shifted right to align its rightmost bit on bit 0. Since the 
    	   divisor will be a power of 2, when a constant for themask is used 
    	   then the compiler is free to replace the divide by a shift.  
    	   	IMPORTANT NOTE: Argument mask is evaluated multiple times 
    	   	IMPORTANT NOTE: Assumes 32 bit integers 
    		Note: the ?: operator on the second line of GET_SUB_FIELD is 
    		needed since otherwise visual C complains of a divide by zero 
    		(it's a false positive, the divide can never happen), the check 
    		should (must?) dissappear suring compilation.  */
    	   /*lint -emacro(506,GET_SUB_FIELD) Constant boolean in mask check*/	
    	   /*lint -emacro(572,GET_SUB_FIELD) False detection of excessive right shift.*/	
    #define SUB_FIELD_DIVISOR(mask)((mask) & ~((mask) << 1u))
    #define GET_SUB_FIELD(val,mask)(((mask)!=0x80000000u)? \
    	(((val) & (mask))/(((mask)!=0x80000000u)?SUB_FIELD_DIVISOR((mask)&~0x80000000):1)): \
    	(((val)&(mask))>>31u))
    

    TEST(subfield_test, mask_offset_0) {
    
        RESET_FFF();
        
        	// Check no mask case.  This is actually an error but it's not detected 
    	//  by the code. We will rely on lint to catch.
        EXPECT_EQ(0u,SUB_FIELD_DIVISOR(0u));
    }
    
    TEST(subfield_test, mask_offset_1) {
    
        RESET_FFF();
        
        	// Check simple 1 bit field with no offset.  Should produce a divider of 1 
        EXPECT_EQ(1u,SUB_FIELD_DIVISOR(1u));
    }
    
    TEST(subfield_test, mask_offset_1x) {
    
        RESET_FFF();
        
        	// Check simple multiple bit field with no offset.  Should produce a divider of 1 
        EXPECT_EQ(1u,SUB_FIELD_DIVISOR(3u));
        EXPECT_EQ(1u,SUB_FIELD_DIVISOR(0xFu));
        EXPECT_EQ(1u,SUB_FIELD_DIVISOR(0xFFu));
    }
    
    TEST(subfield_test, mask_offset_3) {
    
        RESET_FFF();
        
        	// Check simple 1 bit field with a 3 bit offset.  Should produce a divider of 8 
        EXPECT_EQ(8u,SUB_FIELD_DIVISOR(0x8u));
    }
    
    TEST(subfield_test, mask_offset_3x) {
    
        RESET_FFF();
        
        	// Check simple multiple bit field 3 bit offset.  Should produce a divider of 8 
        EXPECT_EQ(8u,SUB_FIELD_DIVISOR(0x18u));
        EXPECT_EQ(8u,SUB_FIELD_DIVISOR(0xF8u));
        EXPECT_EQ(8u,SUB_FIELD_DIVISOR(0xFF8u));
    }
    
    TEST(subfield_test, mask_offset_8) {
    
        RESET_FFF();
        
        	// Check simple 1 bit field with a 8 bit offset.  Should produce a divider of 256 
        EXPECT_EQ(256u,SUB_FIELD_DIVISOR(0x100u));
    }
    
    TEST(subfield_test, mask_offset_8x) {
    
        RESET_FFF();
        
        	// Check simple multiple bit field with a 8 bit offset.  Should produce a divider of 256 
        EXPECT_EQ(256u,SUB_FIELD_DIVISOR(0x300u));
        EXPECT_EQ(256u,SUB_FIELD_DIVISOR(0xF00u));
        EXPECT_EQ(256u,SUB_FIELD_DIVISOR(0xFF00u));
    }
    
    TEST(subfield_test, mask_offset_32) {
    
        RESET_FFF();
        
        	// Check simple 1 bit field with a 3 bit offset.  Should produce a divider of 8 
        EXPECT_EQ(2147483648u,SUB_FIELD_DIVISOR(0x80000000u));
    }
    
    TEST(subfield_test, get_subfield_1) {
    
        RESET_FFF();
        
        	// extract a simple one bit field at different offsets with no other 
    	// bits set 
        EXPECT_EQ(1u,GET_SUB_FIELD(0x1u, 0x1u));
        EXPECT_EQ(0u,GET_SUB_FIELD(0x0u, 0x1u));
        EXPECT_EQ(1u,GET_SUB_FIELD(0x10u, 0x10u));
        EXPECT_EQ(0u,GET_SUB_FIELD(0x0u, 0x10u));
        EXPECT_EQ(1u,GET_SUB_FIELD(0x100u, 0x100u));
        EXPECT_EQ(0u,GET_SUB_FIELD(0x0u, 0x100u));
    }
    
    TEST(subfield_test, get_subfield_1x) {
    
        RESET_FFF();
        
        	// extract a simple one bit field with other bits set. 
        EXPECT_EQ(1u,GET_SUB_FIELD(0x1Fu, 0x10u));
        EXPECT_EQ(0u,GET_SUB_FIELD(0x0Fu, 0x10u));
        EXPECT_EQ(1u,GET_SUB_FIELD(0xF0u, 0x10u));
        EXPECT_EQ(0u,GET_SUB_FIELD(0xE0u, 0x10u));
        EXPECT_EQ(1u,GET_SUB_FIELD(0xFFu, 0x10u));
        EXPECT_EQ(0u,GET_SUB_FIELD(0xEFu, 0x10u));
    }
    
    TEST(subfield_test, get_subfield_4x) {
    
        RESET_FFF();
        
        	// extract a multiple bit field. 
        EXPECT_EQ(1u,GET_SUB_FIELD(0x1Fu, 0xF0u));
        EXPECT_EQ(0u,GET_SUB_FIELD(0x0Fu, 0xF0u));
        EXPECT_EQ(1u,GET_SUB_FIELD(0xF10u, 0xF0u));
        EXPECT_EQ(0xFu,GET_SUB_FIELD(0xFF0u, 0xF0u));
        EXPECT_EQ(0x2u,GET_SUB_FIELD(0x2Fu, 0xF0u));
        EXPECT_EQ(0x5u,GET_SUB_FIELD(0x5Fu, 0xF0u));
        EXPECT_EQ(0x3u,GET_SUB_FIELD(0xF30u, 0xF0u));
        EXPECT_EQ(0x7u,GET_SUB_FIELD(0xF70u, 0xF0u));
        EXPECT_EQ(0xAu,GET_SUB_FIELD(0xFAFu, 0xF0u));
        EXPECT_EQ(0xCu,GET_SUB_FIELD(0xFCCu, 0xF0u));
    }
    
    TEST(subfield_test, get_subfield_32) {
    
        RESET_FFF();
        
        	// extract a single high bit field. 
        EXPECT_EQ(1u,GET_SUB_FIELD(0x80000000u, 0x80000000u));
        EXPECT_EQ(0u,GET_SUB_FIELD(0x0u, 0x80000000u));
    }
    
    TEST(subfield_test, get_subfield_32x) {
    
        RESET_FFF();
        
        	// extract a single high bit field. 
        EXPECT_EQ(2u,GET_SUB_FIELD(0x80000000u, 0xC0000000u));
        EXPECT_EQ(3u,GET_SUB_FIELD(0xF0000000u, 0xC0000000u));
        EXPECT_EQ(0u,GET_SUB_FIELD(0x0u, 0xC0000000u));
    }
    

    Robert

  • Hello Robert,

    I agree some of the files have got the _S and some do not. I am trying to see if there is a time chronology to update of the script that generated the macros.

    Regards
    Amit