/****************************************************************************** *File name : MM_21020.s *Version.Revision: 1.13 *Purpose: * This module contains some functions that deal with data exchange between * Data Memory (32 bit words) and Program Memory (48 bit words), or with memory * access in general. They are written in assembler because standard C memcpy * can not cope with different words size, or just to increase speed *Public Functions: * void from_PM_to_DM (int*, int*, int); * void from_DM_to_PM (int*, int*, int); * void one_PM_to_DM (int*, int*, int*, int*); * int read_word_DM (int*); * void write_word_DM (int*, int); * void from_1DM_to_2DM (int*, int*, int); * void from_2DM_to_1DM (int*, int*, int); * void adicpy (unsigned int *, unsigned int *, unsigned int); * void adicpyMask (void*, const void*, size_t); * void adicpyPM (void*, const void*, size_t); * void copyPatched_AndReset (void* p_1, const void* p_2, size_t number_of_words); *Private Functions: * none *Description: * See the header of the functions *Creation Date & Author: 22-03-2001, SP *Version, Update date & Author: 1.1, 14-02-2002, SP * adapted to PA plan, no change to the code * 1.2, 08-05-2002, SP * added the function read_word_DM (copied from * CRISA's function MEM_ReadDMWord) * 1.3, 26-03-2003, SP * splitting a DM word in two 16 bits words * 1.4, 20-05-2003, SP * added the function write_word_DM * 1.5, 06-10-2004, SP * check on zero length cycles * 1.6, 16-03-2005, SP * new adicpy (substitutes memcpy in all DPU OBSW) * 1.7, 05-08-2005, SP * removed adicpy * 1.8, 25-01-2006, DS and SP * added function copyPatched_AndReset * removed the use of some register that ISR * do not save * 1.9, 25-01-2006, DS and SP * added function copyPatched_AndReset * removed the use of LoopCounter register * 1.10, 26-10-2006, SP * added #ifdef CFM for adicpy * corrected the reset of 21020 after patching * 1.11, 09-11-2006, SP * removed adicpy and #ifdef CFM * 1.12, 15-12-2006, SP * adicpy again * 1.13, 15-12-2006, SP * mask for base APID counter ******************************************************************************/ #include #define BOOT_SEQ_COUNTER 0x1560 /* This two lines are copied from MM_MISC.h */ #define MASK_FOR_APID_SSC 0xABCD0000 /*========================= GLOBAL VAR ======================= _Make_reset; /****************************************************************************** *Function name : from_PM_to_DM *Purpose: * This function moves N (given as third argument) PM words, starting from the * address passed as first argument, in 3*N DM words, starting from the address * given as second argument *Syntax: * from_PM_to_DM (int* p_1, int* p_2, int number_of_words); *Input: * p_1 pointer in PM * p_2 pointer in DM * number_of_words number of PM words to copy in DM *Output: * none *Return: * none *Example: * from_PM_to_DM (p_1, p_2, n); * p_1 points to PM_ADDRESS, p_2 points to DM_ADDRESS, n is 2. * Memory image before calling the function * PM[PM_ADDRESS] = 0x123456789ABC; * PM[PM_ADDRESS+1] = 0xDEF098765432; * DM[DM_ADDRESS... to ...DM_ADDRESS+(n*3-1)] = any_number; * On exit: * PM[...] = not_changed; * DM[DM_ADDRESS] = 0x1234; DM[DM_ADDRESS+1] = 0x5678; DM[DM_ADDRESS+2] = 0x9ABC; * DM[DM_ADDRESS+3] = 0xDEF0; DM[DM_ADDRESS+4] = 0x9876; DM[DM_ADDRESS+5] = 0x5432; * n = not_changed; ******************************************************************************/ .segment/pm seg_pmco; .global _from_PM_to_DM; _from_PM_to_DM: leaf_entry; /* This must appear as the first line in every assembly language routine */ /* Avoid zero length cycles */ r0 = pass r12; if EQ jump nothing_to_do_1 (db); /* The two following lines are executed also in case r12 is zero. However i12 and i4 are scratch registers so their value does not need to be preserved */ i12 = r4; /* r4 contains the 1st parameter */ i4 = r8; /* r8 contains the 2nd parameter */ /* Loop on r12, which contains the 3rd parameter */ from_PMLoop: px = pm(i12,m14); /* After copy i12=i12+1 */ r0 = px2; r1 = FEXT r0 BY 16:16; dm(i4,m6) = r1; r1 = FEXT r0 BY 0:16; dm(i4,m6) = r1; r0 = px1; dm(i4,m6) = r0; r12 = r12 - 1; IF NE jump from_PMLoop (db); nothing_to_do_1: nop; nop; leaf_exit; .endseg; /****************************************************************************** *Function name : from_DM_to_PM *Purpose: * This function moves 3*N (given as third argument) DM words, starting from * the address passed as second argument, in N PM words, starting from the * address given as first argument *Syntax: * from_DM_to_PM (int* p_1, int* p_2, int number_of_words); *Input: * p_1 pointer in PM * p_2 pointer in DM * number_of_words number of PM words to copy from DM *Output: * none *Return: * none *Example: * from_DM_to_PM (p_1, p_2, n); * p_1 points to PM_ADDRESS, p_2 points to DM_ADDRESS, n is 2. * Memory image before calling the function * PM[PM_ADDRESS... to ...PM_ADDRESS+1] = any_number; * DM[DM_ADDRESS] = 0x1234; DM[DM_ADDRESS+1] = 0x5678; DM[DM_ADDRESS+2] = 0x9ABC; * DM[DM_ADDRESS+3] = 0xDEF0; DM[DM_ADDRESS+4] = 0x9876; DM[DM_ADDRESS+5] = 0x5432; * On exit: * PM[PM_ADDRES] = 0x123456789ABC; * PM[PM_ADDRES+1] = 0xDEF098765432; * DM[DM_ADDRESS... to ...DM_ADDRESS+(n*3-1)] = not_changed; * n = not_changed; ******************************************************************************/ .segment/pm seg_pmco; .global _from_DM_to_PM; _from_DM_to_PM: leaf_entry; /* This must appear as the first line in every assembly language routine */ /* Avoid zero length cycles */ r0 = pass r12; if EQ jump nothing_to_do_2 (db); /* The two following lines are executed also in case r12 is zero. However i12 and i4 are scratch registers so their value does not need to be preserved */ i12 = r4; /* r4 contains the 1st parameter */ i4 = r8; /* r8 contains the 2nd parameter */ /* Loop on r12, which contains the 3rd parameter */ from_DMLoop: r0 = dm(i4,m6); /* After copy i4=i4+1 */ r1 = FDEP r0 BY 16:16; r0 = dm(i4,m6); r1 = r1 OR FDEP r0 BY 0:16; px2 = r1; r1 = dm(i4,m6); px1 = r1; pm(i12,m14) = px; r12 = r12 - 1; IF NE jump from_DMLoop (db); nothing_to_do_2: nop; nop; leaf_exit; .endseg; /****************************************************************************** *Function name : one_PM_to_DM *Purpose: * This function moves 1 PM word, at the address passed as 4th argument, in 3 * DM variables whose pointers are passed as the three first arguments *Syntax: * one_PM_to_DM (int* p_1, int* p_2, int* p_3, int* p_4); *Input: * p_1 pointer in DM * p_2 pointer in DM * p_3 pointer in DM * p_4 pointer in PM *Output: * none *Return: * none *Example: * one_PM_to_DM (p_1, p_2, p_3, p_4); * p_1 points to variable Var_1 * p_2 points to variable Var_2 * p_3 points to variable Var_3 * p_4 points to PM_ADDRESS * Memory image before calling the function * PM[PM_ADDRESS] = 0x56749912ABCD; * Var_1, Var_2, Var_3 = any_number; * On exit: * PM[PM_ADDRESS] = no_change; * Var_1 = 0x5674 * Var_2 = 0x9912 * Var_3 = 0xABCD ******************************************************************************/ .segment/pm seg_pmco; .global _one_PM_to_DM; _one_PM_to_DM: leaf_entry; /* This must appear as the first line in every assembly language routine */ i12 = reads(1); /* read the 1st parameter from the stack (address) */ /* Transfer 1 word from PM into the three variables */ px = pm(i12,m13); /* m13 contains 0 by default */ r0 = px2; r1 = FEXT r0 BY 16:16; i4 = r4; dm(i4,m5) = r1; r1 = FEXT r0 BY 0:16; i4 = r8; dm(i4,m5) = r1; i4 = r12; r1 = px1; dm(i4,m5) = r1; leaf_exit; .endseg; /****************************************************************************** * Function name : read_word_DM *Purpose: * This function returns the value contained in the specified DM address. The * code has been copied from CRISA's function MEM_ReadDMWord *Syntax: * int register = read_word_DM (int* p_1); *Input: * p_1 pointer in DM *Output: * none *Return: * register the 32bits DM word ******************************************************************************/ .segment/pm seg_pmco; .global _read_word_DM; _read_word_DM: leaf_entry; /* return dm word*/ i4 = r4; r0 = dm(0, i4); leaf_exit; .endseg; /* End of _read_word_DM */ /****************************************************************************** * Function name : write_word_DM *Purpose: * This function writes a value in the specified DM address. The code has been * copied from CRISA's function MEM_WriteDMWord *Syntax: * write_word_DM (int* p_1, int value); *Input: * p_1 pointer in DM * value value to be written *Output: * none *Return: * none ******************************************************************************/ .segment/pm seg_pmco; .global _write_word_DM; _write_word_DM: leaf_entry; /* Write Dm word */ i4 = r4; dm(0, i4) = r8; leaf_exit; .endseg; /* End of _write_word_DM */ /****************************************************************************** *Function name : from_1DM_to_2DM *Purpose: * This function splits one DM word in two 16 bits words. It is used when * preparing a TM packet. It is assumed that the TM structure is just a * sequence of unsigned int *Syntax: * from_1DM_to_2DM (int* p_1, int* p_2, int number_of_words); *Input: * p_1 pointer to the data field of the TM packet * p_2 pointer in DM to the original data * number_of_words number of DM words *Output: * none *Return: * none *Example: * from_1DM_to_2DM (p_1, p_2, n); * p_1 points to DM_ADDRESS_1, p_2 points to DM_ADDRESS_2, n is 1. * Memory image before calling the function * DM[DM_ADDRESS_1] = any_number; * DM[DM_ADDRESS_2] = 0x12345678; * On exit: * DM[DM_ADDRESS_1] = 0x1234; DM[DM_ADDRESS_1+1] = 0x5678; * DM[DM_ADDRESS_2] = not_changed; * n = not_changed; ******************************************************************************/ .segment/pm seg_pmco; .global _from_1DM_to_2DM; _from_1DM_to_2DM: leaf_entry; /* This must appear as the first line in every assembly language routine */ r2 = i0;/* save i0, r2 is not used in the code */ /* Avoid zero length cycles */ r0 = pass r12; if EQ jump nothing_to_do_3 (db); /* The two following lines are executed also in case r12 is zero. However i4 is a scratch register while i0 has been already saved in r2 */ i0 = r4; /* r4 contains the 1st parameter */ i4 = r8; /* r8 contains the 2nd parameter */ /* Loop on r12, which contains the 3rd parameter */ from_1DMLoop: r0 = dm(i4,m6); r1 = FEXT r0 BY 16:16; dm(i0,m6) = r1; r1 = FEXT r0 BY 0:16; dm(i0,m6) = r1; r12 = r12 - 1; IF NE jump from_1DMLoop (db); nothing_to_do_3: nop; nop; i0 = r2; leaf_exit; .endseg; /* End of _from_1DM_to_2DM */ /****************************************************************************** *Function name : from_2DM_to_1DM *Purpose: * This function restores one DM word from two 16 bits words. It is used when * extracting data from a TC packet. It is assumed that the TC structure is * just a sequence of unsigned int *Syntax: * from_2DM_to_1DM (int* p_1, int* p_2, int number_of_words); *Input: * p_1 pointer to DM destination * p_2 pointer to the data field of the TC packet * number_of_words number of DM words to copy (2*number of TC words) *Output: * none *Return: * none *Example: * from_2DM_to_1DM (p_1, p_2, n); * p_1 points to DM_ADDRESS_1, p_2 points to DM_ADDRESS_2, n is 1. * Memory image before calling the function * DM[PM_ADDRESS_1] = any_number; * DM[DM_ADDRESS_2] = 0x1234; DM[DM_ADDRESS_2+1] = 0x5678; * On exit: * DM[PM_ADDRES_1] = 0x12345678; * DM[DM_ADDRESS_2 to ...DM_ADDRESS_2+1] = not_changed; * n = not_changed; ******************************************************************************/ .segment/pm seg_pmco; .global _from_2DM_to_1DM; _from_2DM_to_1DM: leaf_entry; /* This must appear as the first line in every assembly language routine */ r2 = i0;/* save i0, r2 is not used in the code */ /* Avoid zero length cycles */ r0 = pass r12; if EQ jump nothing_to_do_4 (db); /* The two following lines are executed also in case r12 is zero. However i4 is a scratch register while i0 has been already saved in r2 */ i0 = r4; /* r4 contains the 1st parameter */ i4 = r8; /* r8 contains the 2nd parameter */ /* Loop on r12, which contains the 3rd parameter */ from_2DMLoop: r0 = dm(i4,m6); /* After copy i4=i4+1 */ r1 = FDEP r0 BY 16:16; r0 = dm(i4,m6); r1 = r1 OR FDEP r0 BY 0:16; dm(i0,m6) = r1; r12 = r12 - 1; IF NE jump from_2DMLoop (db); nothing_to_do_4: nop; nop; i0 = r2; leaf_exit; .endseg; /* End of _from_2DM_to_1DM */ /****************************************************************************** *Function name : adicpyMask *Purpose: * This function implements the memcpy code of the ADI21020 library but the * number read is masked with 0xFFFF before writing into destination *Syntax: * adicpyMask (void* p_1, const void* p_2, size_t number_of_words); *Input: * p_1 pointer to DM * p_2 pointer from DM * number_of_words number of DM words *Output: * none *Return: * none *Example: * use as standard memcpy; ******************************************************************************/ .segment/pm seg_pmco; .global _adicpyMask; _adicpyMask: leaf_entry; /* This must appear as the first line in every assembly language routine */ r1 = i0; /* save i0, r1 is not used in the code */ /* Avoid zero length cycles */ r12 = pass r12; /* Test for zero input; save i5 */ if EQ jump nothing_to_do_6 (db); /* The two following lines are executed also in case r12 is zero. However i4 is a scratch register while i0 has been already saved in r1 */ i4 = r8; /* r8 Point to input*/ i0 = r4; /* r4 Point to output*/ r0 = 0xFFFF; /* Mask */ AdiMaskLoop: r2 = dm(i4,m6); r2 = r2 AND r0; dm(i0,m6) = r2; r12 = r12 - 1; IF NE jump AdiMaskLoop (db); nothing_to_do_6: nop; nop; i0 = r1; leaf_exit; .endseg; /****************************************************************************** *Function name : adicpyPM *Purpose: * This function implements the memcpy code of the ADI21020 library but it * works on PM *Syntax: * adicpyPM (void* p_1, const void* p_2, size_t number_of_words); *Input: * p_1 pointer to PM * p_2 pointer from PM * number_of_words number of PM words *Output: * none *Return: * none *Example: * use as standard memcpy; ******************************************************************************/ .segment/pm seg_pmco; .global _adicpyPM; _adicpyPM: leaf_entry; /* This must appear as the first line in every assembly language routine */ r1 = i11; /* save i11, r1 is not used in the code */ i12 = r8; /* Point to input*/ i11 = r4; /* Point to output*/ px = pm(i12,m14); pm(i11,m14) = px; r12 = r12 - 1; IF NE jump (pc,-3) (db); nop; nop; r0 = dm(_Make_reset); r0 = pass r0; /* (Make_reset == 0) */ if EQ jump no_reset (db); nop; nop; /* Here we prepare the mask to distinguish start from OBSW instead of from BSW */ i12 = BOOT_SEQ_COUNTER; r0 = pm(i12,m13); /* i12 does not change */ r3 = MASK_FOR_APID_SSC; r0 = r0 + r3; pm(i12,m14) = r0; /* For AVM2 onward, the following line makes a reset of 21020, other lines are ignored. In AVM1 nothing happens */ i1 = 0x82000000; r3 = 0x60; dm(i1,m6) = r3; /* In AVM1 this line makes a SW reset of 21020*/ jump(0x08)(db); nop; nop; no_reset: i11 = r1; leaf_exit; .endseg; /****************************************************************************** *Function name : copyPatched_AndReset *Purpose: * This function calls clone of adicpyPM and reset 21020 * *Syntax: * copyPatched_AndReset (void* p_1, const void* p_2, size_t number_of_words); *Input: * p_1 pointer to destination start address * p_2 pointer to source start address * number_of_words number of PM words *Output: * none *Return: * none *Example: * used by function copy_OBSW_image; ******************************************************************************/ .segment/pm seg_pmco; .global _copyPatched_AndReset; _copyPatched_AndReset: leaf_entry; /* This must appear as the first line in every assembly language routine */ // disable interrupts bit clr mode1 0x1000; nop; nop; /* Avoid zero length cycles */ r12 = pass r12; /* Test for zero input */ if EQ jump nothing_to_do_8 (db); nop; nop; dm(_Make_reset) = m6; /* to perform 21020 reset after adicpy_PM */ r0=dm(_adicpy_len); r0=r8-r0; /* StartDestAddr - adicpy_len */ i8=r0; r2=i6; i6=i7; jump(m13,i8)(db); /* jump (r8 - dm(_adicpy_len))(db) */ dm(i7,m7)=r2; dm(i7,m7)=pc; nothing_to_do_8: leaf_exit; .endseg;