<font color='#0000FF'>

        $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
