Email: Password: Remember Me | Create Account (Free)

Back to Subject List

Old thread has been locked -- no new posts accepted in this thread
???
06/08/03 14:24
Read: times


 
#47811 - RE: How to keep tabs on checksum from C code
Responding to: ???'s previous message
Jerson:
Here is the basic scheme that I use to do what you want:

1) Instead of trying to find the End of code location I put the label for the checksum location at the last two bytes of the actual ROM/EPROM/FLASH space. This is easy since the hardware for a typical setup if static.

2) I put the checksum label in its own source file. Here is typical Keil C code for this...


    /* Flash checksum storage location */
    unsigned int code rom_check = {
    #include "check_code.h"
                                  };


3) Then next I have the small include file check_code.h which will look like this. Initally when I first start a project this file must be hand edited so that the above include file works.


               0xB72A     // Checksum Value 


4) Next I use a command line option to the Keil linker to fix the location of small source file mentioned in #2 above to an address that is just at the end of the programmable code memory space. In the Keil tools it is not allowed to use the AT attribute on the declaration of the flash chceck variable becasue this is an initialized variable and so the linker command must be given. Your C compiler may support the AT for initialized data and so the linker command nay bot be needed. [I'll not document the actual linker command here as it is covered in the linker manual].

5) Then I include another small source file that is written in assembly language that can compute and check the code space check code at run time. It simply checks all across the whole memory space. Here is the code I used on one project:


        $NOMOD51
        $NOCOND
                NAME    ?BIT?ROM
        ;
        ;
        ; Standard SFR Symbols required here
        ;
        ACC     DATA    0E0H
        B       DATA    0F0H
        DPL     DATA    82H
        DPH     DATA    83H
        WDTCN   DATA    0FFH                    ; Cygnal watch dog timer control register
        ;
        ;
        ; Cygnal 'F126 bank access information
        ;
        PSBANK          EQU     0B1H            ; PSBANK Address SFR
        BANK_TOP        EQU     3               ; top bank number
        BANK_START      EQU     08000H          ; start address to access a bank
        BANK_END        EQU     0FFFFH          ; end address within a bank
        BANK_CHECK_SUM  EQU     0FBFCH          ; checksum location in the end of
                                                ; final bank, These two bytes are imediately
                                                ; infront of the two bytes that are the flash 
                                                ; protect bytes, which is then followed by the 
                                                ; Cygnal reserved area.
        BIT_ROM_PASSED  EQU     000H            ; return value indicators
        BIT_ROM_FAILED  EQU     0FFH
        ;
        ;
        ; The Flash ROM for the CDU Device consists of 128K Bytes of flash organized
        ; as four logical banks. The address space from 00000H->07FFFH is known as the
        ; common bank and is addressable via the data pointer as addresses 0000->7FFF.
        ; On board Cygnal the processor there is a bank select register called PSBANK that
        ; is a special function register that allows the selection of banks of the FLASH
        ; into the address space of the DPTR access from 8000->FFFF. The table below
        ; describes the bank switch scheme and the banks of the Cygnal FLASH that are
        ; accessible. 
        ;
        ;   PSBANK         DPTR/MOVC Access             DPTR/MOVC Access
        ;   Register         0000H->8000H                 8000H->FFFFH
        ;   --------    -------------------------    -------------------------
        ;    00H         Bank 0 - 00000H->07FFFH      Bank 0 - 00000H->07FFFH
        ;    11H         Bank 0 - 00000H->07FFFH      Bank 1 - 08000H->0FFFFH
        ;    22H         Bank 0 - 00000H->07FFFH      Bank 2 - 10000H->17FFFH
        ;    33H         Bank 0 - 00000H->07FFFH      Bank 3 - 18000H->1FBFFH
        ;
        ; Note that bank 3 is 1K short of a full 32K becasue the Cygnal part
        ; reserves the last 1K of space for special factory functions.
        ;
        ; Add up the contents of the FLASH modulo 16                     
        ; this will be done from bottom to top of FLASH memory. The inserted
        ; FLASH checksum is located at the last two bytes of the top flash bank
        ; just before the reserved area and the flash security bytes.
        ;

                PUBLIC  _BIT_ROM_TEST
                EXTRN   DATA(flash_checksum)

        BIT_ROM_TEST    SEGMENT CODE
                RSEG    BIT_ROM_TEST

        _BIT_ROM_TEST:
                CLR     A                       
                MOV     PSBANK,A                ; start with bank 0
                MOV     R0,A                    ; clear checksum accumulator
                MOV     R1,A
                MOV     R2,#0                   ; track the banks in R2
        BANKLOOP:
                MOV     DPTR,#08000H            ; start address in bank
                MOV     A,R2                    ; setup the bank address
                SWAP    A                       ; make as 2 equal nibbles
                ORL     A,R2
                MOV     PSBANK,A                ; set the bank address
        LOOP:
                MOV     WDTCN, #0A5H            ; reset the watch dog timer
                CLR     A                       ; Clear out A prior to fetch
                MOVC    A,@A+DPTR               ; get the data pointed to by DPTR into ACC
                ADD     A,R0                    ; add low byte just received into low byte
                JNC     NO_CARRY                ; if carry not set then don't increment r1
                INC     R1                      ; else increment r1
        ;
        NO_CARRY:
                MOV     R0,A                    ; save results of this add in r0
                INC     DPTR                    ; inc the dptr
        ;
                CJNE    R2,#BANK_TOP,BANK0      ; not working in the top bank
                JMP     BANK1                   ; do end checking for top bank  
        BANK0:
                MOV     A,DPL                   ; When the DPTR loops from FFFF to 0000 then
                CJNE    A,#000H,LOOP            ; the bank is done. The DPL and DPH must be
                MOV     A,DPH                   ; placed into the ACC and tested seperately 
                CJNE    A,#000H,LOOP            ; if DPH equals 00h then done else keep going
        ;
                INC     R2                      ; advance to next bank
                JMP     BANKLOOP
        ;
        BANK1:
                CLR     C
                MOV     A,DPL                   ; test for up to checksum location
                SUBB    A,#LOW(BANK_CHECK_SUM)
                MOV     A,DPH
                SUBB    A,#HIGH(BANK_CHECK_SUM)
                JC      LOOP                    ; more data to sum up yet
        ;
        ;
        ; compare r0 to rom_end and r1 to rom_end-1. Note that here the
        ; DPTR is pointing to the BANK_CHECK_SUM location.
        ;
        COMP:
                MOV     R7,#BIT_ROM_PASSED      ; show default return for passed
        ;
                CLR     A                       ; Clear a prior to MOVC
                MOVC    A,@A+DPTR               ; get checksum byte into acc
                MOV     flash_checksum,A        ; save high order byte of computed checksum
                XRL     A,R1                    ; IF bytes are equal ACC will be zero
                JZ      COMP1
                MOV     R7,#BIT_ROM_FAILED      ; show return for failed
        ;
        COMP1:
                CLR     A                       ; Clear a prior to MOVC
                INC     DPTR                    ; point to last byte in FLASH
                MOVC    A,@A+DPTR               ; get checksum byte into acc
                MOV     flash_checksum+1,A      ; save low order byte of checksum
                XRL     A,R0                    ; IF bytes are equal ACC will be zero
                JZ      ROM_PASS                ; IF ACC not zero then ROM CHECK FAIL
                MOV     R7,#BIT_ROM_FAILED      ; show return for failed
        ;
        ROM_PASS:
                MOV     A,#011H                 ; set bank register to reset value
                MOV     PSBANK,A

                RET

                END


6) The above routine is called from the C code to validate the check code.

7) At built time I have a user utility function that I made that is installed in the IDE tools menu so that it is easy to invoke. This is a batch file that runs a sequence of small programs that perform the following functions: Convert the linker OMF object file to hex format....Convert the hex format to binary format....Run a utility that reads the binary image and expands it to full specified code memory size and then calculates the checksum for the whole of the code space. The checksum utility writes out the small include file mentioned in step #3 above. Some of the programs that are used in the batch file are Keil tools. I had problems with the Keil Hex->Bin converter running under Win2000 so I made a new HEX2BIN compiled as a WIN32 console application. The checksum calculator is also a custom utility program that I wrote. (If you want ehther or both of these utilities I would be happy to share them if you send me an email). Here is a sample of this batch file.


    oc51 cdu
    oh51 cdu.b01 hexfile (cdu_01.hex)
    oh51 cdu.b02 hexfile (cdu_02.hex)
    oh51 cdu.b03 hexfile (cdu_03.hex)
    hex2bin cdu_01.hex cdu_00.bin ff 0000 8000
    hex2bin cdu_01.hex cdu_01.bin ff 8000 8000
    hex2bin cdu_02.hex cdu_02.bin ff 8000 8000
    hex2bin cdu_03.hex cdu_03.bin ff 8000 7BFC
    copy cdu_00.bin /b + cdu_01.bin /b + cdu_02.bin /b + cdu_03.bin /b cdu_image.bin /b
    ChkSumCalc cdu_image.bin check_code.h
    type check_code.h
    echo Press a key to continue...
    pause


8) Whenever I build the code I first compile and link it. Then I use the user tool entry in the IDE menu to run the batch file described in #7 above. Finally I run the compiler/linker again. This causes the proper checksum to be inserted into the program image. The advantage of my approach is that the proper checksum is now in the OMF object file and the program will have the proper checksum while it is being run with a debugger or emulator. If your IDE or build process is a smart make then the second compile step is very fast since only the small source file mentioned in step #2 must be re-compiled. I use the Cygnal IDE and its make is a dumb make that rebuilds every file each time so my double build process takes an extra bit of time but it is not unbearable.

9) Obviously an example for processing a single bank code image would be just a little bit simpler but the same comcept applies.

Hope this helps.
Michael Karas


List of 3 messages in thread
TopicAuthorDate
How to keep tabs on checksum from C code            01/01/70 00:00      
   RE: How to keep tabs on checksum from C code            01/01/70 00:00      
      RE: How to keep tabs on checksum from C code            01/01/70 00:00      

Back to Subject List