| ??? 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 |
| Topic | Author | Date |
| 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 |



