View previous topic :: View next topic |
Author |
Message |
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
Int16 array copy with byte swaping |
Posted: Sat May 19, 2007 12:12 pm |
|
|
I'm looking for a way to copy a large array of Int16 data to another array while swapping the byte order or the Int16 elements of the array. This is part of several functions I am trying to optimize in a MODBUS driver. I have been using arrays for indirect addressing while incrementing an array index. I think this could be done more effectively using pointers and simply incrementing the pointers.
This is an example of code I have been using.
Code: | /***********************************************************
* COMM1 Function 3 *
***********************************************************/
/* evaluate for optimizations */
Void COMM1_Function_3(Void)
{ Const Int16 Max_Reg_Count=(COMM1_Buff_Size-9)/2; // Limit on count based on buffer size
COMM1.Start=Make16(COMM1_Buffer[2],COMM1_Buffer[3]); // Little indian conversion
COMM1.Count=Make16(COMM1_Buffer[4],COMM1_Buffer[5]); // Little indian conversion
if(COMM1.Count>Max_Reg_Count) // Test count of registers aginst buffer size
COMM1.End=REG_Map_Size+1; // Set data range error condition
else
COMM1.End=COMM1.Start+COMM1.Count; // Ending register address
if(COMM1.CRClo_Index!=6) // Check for a packet formating error
COMM1.End=REG_Map_Size+1; // Set data range error condition
if(COMM1.End<=REG_Map_Size) // Check aginst size of reg map
{ COMM1.Index=3; // Set the index to the first byte
COMM1_Buffer[2]=COMM1.Count*2; // Data Byte Count
for(COMM1.y=COMM1.start;COMM1.y<COMM1.End;COMM1.y++)
{ COMM1.x=(COMM1.y*2)+1;
COMM1_Buffer[COMM1.Index] = REG_Map[COMM1.x];
COMM1.Index++;
--COMM1.x;
COMM1_Buffer[COMM1.Index] = REG_Map[COMM1.x];
COMM1.Index++;
}
COMM1.CRChi_Index=COMM1.Index+1;
}
else
{ bit_set(COMM1_Buffer[1],7); // Report_Exception
if(COMM1.CRClo_Index==6) // Valid packet size
COMM1_Buffer[2]=Illegal_Data_Address; // Data range exception type
else
COMM1_Buffer[2]=Illegal_Data_Value; // Packet formating exception type
COMM1.CRChi_Index=4; // Index CRChi
}
} |
I think the code within the for loop in the middle can be greatly improved. |
|
|
future
Joined: 14 May 2004 Posts: 330
|
|
Posted: Sat May 19, 2007 1:28 pm |
|
|
I would declare pointers to COMM1_Buffer[] and REG_Map[], load them in FSR0 and FSR1 and use POSTINC/PREINC/INDF.
The compiler does a poor job using only FSR0 for all array access.
I could not understand the loop and what it does, but I think the idea is valid. |
|
|
libor
Joined: 14 Dec 2004 Posts: 288 Location: Hungary
|
|
Posted: Sun May 20, 2007 6:33 pm |
|
|
Code: | #byte POSTINC0=0xFEE
#byte POSTINC1=0xFE6
#byte FSR0H=0xFEA
#byte FSR0L=0xFE9
#byte FSR1H=0xFE2
#byte FSR1L=0xFE1
//this function copies the memory from src to dest swapping byte order
void memcpy_swap(int8 *dest, int8 *src, int8 n) { // n number of words to copy
int16 temp;
#asm
movff &dest+1, FSR1H
movff dest, FSR1L
movff &src+1, FSR0H
movff src, FSR0L
loop:
movff POSTINC0, temp
movff POSTINC0, &temp+1
movff &temp+1, POSTINC1
movff temp, POSTINC1
decfsz n
goto loop
#endasm
} |
|
|
|
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
|
Posted: Sun May 20, 2007 11:10 pm |
|
|
This is what I ended up with. I think it is as tightly optimized as it's going to be but I think it could be more readable. I'm not sure that can be fixed. I think I was unclear in what I needed to do but your replies got me going in the right direction. This code copies Int16 values from one array to another while reversing the byte order of the Int16 elements. Change Int16 element values from big Indian to little Indian. Code: | /***********************************************************
* COMM1 Function 3 *
***********************************************************/
Void COMM1_Function_3(Void)
{ #Byte Target_Inc = 0x0FE6 // Increments FSR1 after use
#byte Source_Inc = 0x0FDE // Increments FSR2 after use
#byte Source_Dec = 0x0FDD // Decrements FSR2 after use
Int16 Target_Address;
#locate Target_Address = 0x0FE1 // FSR1 address
Int16 Source_Address;
#locate Source_Address = 0x0FD9 // FSR2 address
Const Int16 Max_Reg_Count=(COMM1_Buff_Size-9)/2; // Limit on count based on buffer size
COMM1.Start=Make16(COMM1_Buffer[2],COMM1_Buffer[3]); // Little indian conversion
COMM1.Count=Make16(COMM1_Buffer[4],COMM1_Buffer[5]); // Little indian conversion
if(COMM1.Count>Max_Reg_Count) // Test count of registers aginst buffer size
COMM1.End=REG_Map_Size+1; // Set data range error condition
else
COMM1.End=COMM1.Start+COMM1.Count; // Ending register address
if(COMM1.CRClo_Index!=6) // Check for a packet formating error
COMM1.End=REG_Map_Size+1; // Set data range error condition
if(COMM1.End<=REG_Map_Size) // Check aginst size of reg map
{ COMM1_Buffer[2]=COMM1.Count*2; // Data Byte Count
Target_Address = &COMM1_Buffer[3];
Source_Address = (COMM1.Start*2) + ®_Map[1];
While(COMM1.Count) // Number of Int16 to be copied
{ Target_Inc = Source_Dec; // Low byte copied
Target_Inc = Source_Inc; // High byte copied
COMM1.X = Source_Inc; // Address next byte to be copied
COMM1.X = Source_Inc; // Address next byte to be copied
--COMM1.Count;
}
COMM1.CRChi_Index=COMM1_Buffer[2];
COMM1.CRChi_Index+=5;
}
else
{ bit_set(COMM1_Buffer[1],7); // Report_Exception
if(COMM1.CRClo_Index==6) // Valid packet size
COMM1_Buffer[2]=Illegal_Data_Address; // Data range exception type
else
COMM1_Buffer[2]=Illegal_Data_Value; // Packet formating exception type
COMM1.CRChi_Index=4; // Index CRChi
}
}
|
|
|
|
|