This if file "malloc.asm". It is an optional substitution for the file "malloc.c". It is much more optimized, but works only for PIC18 in extended mode with Microchip MPLAB-C18.
;=============================================================================== ; This file is part of "Heap Management For Small Microcontrollers". ; v1.05 (2009-06-29) ; isaacbavaresco@yahoo.com.br ;=============================================================================== ; Copyright (c) 2007-2009, Isaac Marino Bavaresco ; All rights reserved. ; ; Redistribution and use in source and binary forms, with or without ; modification, are permitted provided that the following conditions are met: ; * Redistributions of source code must retain the above copyright ; notice, this list of conditions and the following disclaimer. ; * Neither the name of the author nor the ; names of its contributors may be used to endorse or promote products ; derived from this software without specific prior written permission. ; ; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY ; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ; DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ;=============================================================================== #include <P18CXXX.INC> ;=============================================================================== radix decimal ;=============================================================================== #include <heap_config.h> ;=============================================================================== #if USING_FREE_RTOS == 1 ;------------------------------------------------------------------------------- extern vTaskSuspendAll extern xTaskResumeAll #define LOCALS_SIZE 4 DISABLE_INTERRUPTS macro call vTaskSuspendAll endm RESTORE_INTERRUPTS macro call xTaskResumeAll endm ;------------------------------------------------------------------------------- #else ; USING_FREE_RTOS == 1 ;------------------------------------------------------------------------------- #define LOCALS_SIZE 5 DISABLE_INTERRUPTS macro ; Aux = INTCON & 0xc0; movlw 0xc0 andwf INTCON,w,ACCESS movwf [Aux+0] ; INTCON &= 0x3f; movlw 0x3f andwf INTCON,f,ACCESS endm RESTORE_INTERRUPTS macro ; INTCON |= Aux; movf [Aux+0],w iorwf INTCON,f,ACCESS endm ;------------------------------------------------------------------------------- #endif ; USING_FREE_RTOS == 1 ;=============================================================================== ALLOC code ;=============================================================================== #define Length 0 #define p 4 #define q 6 #define Aux 8 extern __freelist extern vTaskSuspendAll extern xTaskResumeAll ;=============================================================================== global malloc ; void ram *malloc( sizeram_t Length ) malloc: movff FSR2L,POSTINC1 movff FSR2H,POSTINC1 movff FSR1L,FSR2L movff FSR1H,FSR2H subfsr 2,4 ; { ; struct _AllocBlock ram *p,*q; ; #if USING_FREE_RTOS != 1 ; unsigned char Aux; ; #endif // USING_FREE_RTOS != 1 addfsr 1,LOCALS_SIZE ; // We will not allocate 0 bytes. ; if( Length == 0 ) movf [Length+0],w iorwf [Length+1],w bnz NotZero ; // The allocation failed. ; return NULL; clrf PRODL,ACCESS clrf PRODH,ACCESS bra Ret NotZero: ; // // The length should always be even. (Not for 14 or 16 bit (program word) PICs). ; // Length = ( Length + 1 ) & -2; ; ; infsnz [Length+0],f ; incf [Length+1],f ; bcf [Length+0],0 ; #if defined __18CXX || defined _PIC18 ; // The length should be at least 2. (Not for 14 bit (program word) PICs) ; if( Length < sizeof __freelist.Next ) ; Length = sizeof __freelist.Next; ; #endif // defined __18CXX || defined _PIC18 movlw 2 subwf [Length+0],w movlw 0 subwfb [Length+1],w bc TwoOrMore movlw 2 movwf [Length+0] TwoOrMore: ; DISABLE_INTERRUPTS(); DISABLE_INTERRUPTS ; // Then we iterate trough the free list to find a suitable block. ; for( q = &__freelist,p = __freelist.Next; p != NULL && p->Length < Length; q = p, p = p->Next ) ; ; // Empty statement movlw low __freelist ; for( q = &__freelist, movwf [q+0] movlw high __freelist movwf [q+1] movff __freelist+2,FSR0L ; p = __freelist.Next; movff __freelist+3,FSR0H Loop: movf FSR0L,w,ACCESS ; p != NULL iorwf FSR0H,w,ACCESS bz Fail movf [Length+0],w ; && p->Length < Length; subwf POSTINC0,w,ACCESS movf [Length+1],w subwfb POSTDEC0,w,ACCESS bc Found movf FSR0L,w,ACCESS ; q = p, movwf [q+0] movf FSR0H,w,ACCESS movwf [q+1] addfsr 0,2 ; p = p->Next ); movf POSTINC0,w,ACCESS movff INDF0,FSR0H movwf FSR0L,ACCESS bra Loop ; // If p is NULL is because there is no suitable block. ; if( p == NULL ) ; { ; RESTORE_INTERRUPTS(); ; // The allocation failed. ; return NULL; ; } #if USING_FREE_RTOS == 1 Fail: clrf [p+0] clrf [p+1] #else ; USING_FREE_RTOS == 1 Fail: clrf PRODL,ACCESS clrf PRODH,ACCESS #endif ; USING_FREE_RTOS == 1 bra Epilog ; // If the block length is not enough to be splitted, we allocate the whole block. ; if( p->Length < Length + sizeof( struct _AllocBlock )) ; { Found: movf FSR0L,w movwf [p+0] movf FSR0H,w movwf [p+1] movlw 0x04 addwf [Length+0],w movwf PRODL,ACCESS movlw 0x00 addwfc [Length+1],w movwf PRODH,ACCESS movf PRODL,w,ACCESS subwf POSTINC0,w,ACCESS movf PRODH,w,ACCESS subwfb POSTDEC0,w,ACCESS bc SplitBlock ; // Remove the block from the free list. ; q->Next = p->Next; AllocateWhole: addfsr 0,2 movff POSTINC0,PRODL movff POSTDEC0,PRODH movsf [q+0],FSR0L movsf [q+1],FSR0H addfsr 0,2 movff PRODL,POSTINC0 movff PRODH,POSTDEC0 bra Finish ; } ; // We have to split the block. ; else ; { #if ALLOCATE_FROM_BEGINNING == 1 ; // Make the previous block point to the remaining of the block being split. ; q->Next = (struct _AllocBlock RAM *)( (unsigned char RAM *)p + Length + sizeof __freelist.Length ); SplitBlock: movsf [q+0],FSR0L movsf [q+1],FSR0H addfsr 0,2 movf [p+0],w addwf [Length+0],w movwf [q+0] movf [p+1],w addwfc [Length+1],w movwf [q+1] movlw 2 addwf [q+0],f movlw 0 addwfc [q+1],f ; // Make q point to the remaining of the block being split. ; q = q->Next; movsf [q+0],POSTINC0 movsf [q+1],POSTDEC0 ; // Set the lenght of the remaining of the block being split. ; q->Length = p->Length - Length - sizeof __freelist.Length; movsf [p+0],FSR0L movsf [p+1],FSR0H movf [Length+0],w subwf POSTINC0,w,ACCESS movwf PRODL,ACCESS movf [Length+1],w subwfb POSTDEC0,w,ACCESS movwf PRODH,ACCESS movlw 2 subwf PRODL,f,ACCESS movlw 0 subwfb PRODH,f,ACCESS movsf [q+0],FSR0L movsf [q+1],FSR0H movff PRODL,POSTINC0 movff PRODH,POSTDEC0 ; // Set the new block length. ; p->Length = Length; movsf [p+0],FSR0L movsf [p+1],FSR0H movsf [Length+0],POSTINC0 movsf [Length+1],POSTINC0 ; // Make the remaining of the block being split point to where the original block pointed. ; q->Next = p->Next; movff POSTINC0,PRODL movff POSTDEC0,PRODH movsf [q+0],FSR0L movsf [q+1],FSR0H addfsr 0,2 movff PRODL,POSTINC0 movff PRODH,POSTDEC0 #else ; ALLOCATE_FROM_BEGINNING == 1 ; // Make p point to the begining of the new block. ; pTemp = (struct _AllocBlock ram *)( (unsigned char ram *)p + p->Length - Length ); SplitBlock: movf POSTINC0,w,ACCESS addwf [p+0],f movf POSTDEC0,w,ACCESS addwfc [p+1],f movf [Length+0],w subwf [p+0],f movf [Length+1],w subwfb [p+1],f ; // Reduce the original block length. ; p->Length -= Length + sizeof __freelist.Length; movf [Length+0],w subwf POSTINC0,f,ACCESS movf [Length+1],w subwfb POSTDEC0,f,ACCESS movlw 0x02 subwf POSTINC0,f,ACCESS movlw 0x00 subwfb POSTDEC0,f,ACCESS ; // Set the new block length. ; p = pTemp; movsf [p+0],FSR0L movsf [p+1],FSR0H ; p->Length = Length; movsf [Length+0],POSTINC0 movsf [Length+1],POSTDEC0 #endif ; ALLOCATE_FROM_BEGINNING == 1 ; } ; ; RESTORE_INTERRUPTS(); ; // return the address of the data area of the block. ; return (unsigned char RAM *)p + sizeof __freelist.Length; ; } #if USING_FREE_RTOS == 1 Finish: movlw 0x02 addwf [p+0],f movlw 0x00 addwfc [p+1],f Epilog: RESTORE_INTERRUPTS movsf [p+0],PRODL movsf [p+1],PRODH #else ; USING_FREE_RTOS == 1 Finish: movlw 0x02 addwf [p+0],w movwf PRODL,ACCESS movlw 0x00 addwfc [p+1],w movwf PRODH,ACCESS Epilog: RESTORE_INTERRUPTS #endif ; USING_FREE_RTOS == 1 Ret: subfsr 1,LOCALS_SIZE + 1 movff POSTDEC1,FSR2H movff INDF1,FSR2L return 0 ;=============================================================================== end ;===============================================================================