⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 l51_bank.a51

📁 KEIL7.0完全破解版、中文补丁_keil下载
💻 A51
字号:
; $Id: //depot/software/FC220/SDK/UV2/C51/lib/Triscend/L51_BANK.A51#2 $
;
; L51_BANK.A51
;_________________________________________________________________________
;* Copyright (c) 1999 Triscend Corporation. All rights reserved. Reproduction
;* or translation of this work beyond that permitted in Section 117 of the 1976
;* United States Copyright Act without the express written permission of the
;* copyright owner is unlawful. Requests for further information should be
;* addressed to Permission Department, Triscend Corporation. The purchaser
;* may make back up copies for his/her own use and modify and/or redistribute
;* as long as this copyright notice appear in all copies. The Publisher assumes
;* no responsibility for errors, omissions, or damages, caused by the use of
;* these programs or from the use of the information contained herein.
;==========================================================================
;
;--------------------------------------------------------------------------
; This code banking library allows code banking on Triscend Corporation's
; E5 family of programmable microprocessors.  This library is based on the
; code banking library provided by Keil Software, but has been modified to
; support code mapping using the CODE mapper 1.
;
; This library allows for a maximum of 32 banks to be used.  This allows up
; to 2MB code space to be addressable.  This limitation comes from Keil's 
; BL51 code banking linker which includes support for only up to 32 banks. 
; If the BL51 linker is ever changed to support a greater number of banks,
; this library will allow the use of up to 63 banks.  Some work was even
; done to allow this library to support up to 128 banks, but this has not
; yet been fully implemented.  If more than 32 banks are required, then a
; bank switching function must be created manually, without the benefit of
; this code banking library.
;
; The SWITCHBANK symbol allows for explicitly calling for bank-switching in
; C programs.
;   prototype:  extern switchbank (unsigned char bank_number);
;
; The way the code banking works is pretty remarkable.  When your program
; calls a function that is known to be accessible by another bank (even if
; the called function is in the same bank), instead of jumping directly to
; that function, the LCALL instruction instead jumps to a table that the
; BL51 creates.  (Note: the LCALL does push the return address into the
; stack.)  The table moves the called function's address to DPTR, then
; jumps to the ?B_BANKn (where n is bank number that the called function
; resides in).  There, the program determines if the bank that the called
; function resides in is the same as the current bank.  If so, it jumps to
; the address in DPTR.  If not, it's going to need to switch banks, so it
; pushes the address of the SWITCH code needed to return to the current
; bank after the called function completes.  It then pushes the address of
; the called function (from DPTR).  It then jumps to SWITCHn (where n is
; the bank number that the called function resides in.)  SWITCHn switches
; banks by writing to the code mapper and updating ?B_CURRENTBANK and then
; returns (which jumps to the address indicated by the top two bytes in the
; stack-- the called functions address!)  The called function does its
; business and then returns (which jumps to the address indicated by the
; next two bytes in the stack-- the code to return to the caller's bank!) 
; The program then switches back to the original bank and returns again,
; which brings us back to the proper location in the caller function.  
;
; The amazing thing about the code banking library is that if the called
; function calls another function that requires a bank switch, all the
; proper return addresses are retained on the stack, in the proper order. 
; So returning after multiple bank switches is handled correctly.  The
; other amazing thing is that all the code banking is handled using only
; two registers, DPTR and the accumulator(A/ACC).  Note: The fine people
; at Keil Software developed the algorithm; Triscend merely modified it
; to switch banks using the code mapper.
;
;==========================================================================

;$NOCOND DEBUGPUBLICS

;** Configuration Section *************************************************
; The values of the constants in this box should be modified by the user to
; suit the specific application using this code banking library.
;
?B_NBANKS       SET     16       ; Define number of banks needed.
;                                ; The maximum number of banks that this
;                                ; library can support at this time is
;                                ; 32. 
;
?B_RTX          EQU     0        ; 0 for applications without RTX-51 FULL
;                                ; 1 for applications using RTX-51 FULL
;  For RTX-51 FULL, the library must put in code to disable the interrupts
;  during the two instructions that actually do the bank switching.
;
;**************************************************************************

; Define for Triscend CODE Mapper 1 Addresses for Code Banking
?B_CMAP1_TAR_0  EQU     0FF02H   ; Target Address LSB
?B_CMAP1_TAR_1  EQU     0FF03H   ; Target Address middle byte
?B_CMAP1_TAR_2  EQU     0FF04H   ; Target Address MSB

                NAME    ?BANK?SWITCHING

                PUBLIC  ?B_NBANKS, ?B_CURRENTBANK
                PUBLIC  _SWITCHBANK

;------------------------------------------------------------------------------
; These are here for compatibility with RTX FULL.  They're not used within
; the library itself.
                PUBLIC  ?B_MODE, ?B_MASK
                PUBLIC  ?B_FACTOR

?B_MODE         EQU     4               ; 4 for user-provided bank switch code
?B_FACTOR       EQU     1

; generate Mask and Bank Number Information
IF      ?B_NBANKS <= 2
  ?B_MASK          EQU     00000001B
ELSEIF  ?B_NBANKS <= 4
  ?B_MASK          EQU     00000011B
ELSEIF  ?B_NBANKS <= 8
  ?B_MASK          EQU     00000111B
ELSEIF  ?B_NBANKS <= 16
  ?B_MASK          EQU     00001111B
ELSE
  ?B_MASK          EQU     00011111B
ENDIF     
;------------------------------------------------------------------------------

; make sure that ?B_NBANKS is 2, 4, 8, 16, or 32
?B_NBANKS       EQU     (?B_NBANKS + ?B_MASK) AND (NOT ?B_MASK)


;------------------------------------------------------------------------------
?BANK?DATA      SEGMENT DATA
                RSEG    ?BANK?DATA
?B_CURRENTBANK: DS      1

;------------------------------------------------------------------------------
                ; This macro is repeated once for every bank specified by
                ; ?B_NBANKS.  The code contained in this macro is called
                ; when a function that can be called from another bank is
                ; called.  The code then determines if the function called
                ; is in the current bank or not and takes the appropriate
                ; action.
                ;
                ; If the function being called is in the current bank, then
                ; the program jumps directly to that function.  If not, it
                ; needs to prepare to switch banks.
                ;
                ; As preparation for a bank switch, the code must push several
                ; addresses into stack for the return statements: 
                ;   the address of the function we are calling
                ;   the address of the code for returning to this bank after
                ;     the called function returns.
                ;
                ; Once values are pushed into the stack, jump to the code
                ; for switching banks.
                ;
                ; Address for returning to this bank after function returns
                ; is: 
                ;   High byte: page number of ?BANK?SWITCH segment 
                ;              (plus 1 if the current bank is greater than 64)
                ;   Low byte:  ?B_CURRENTBANK * 4   if ?B_NBANKS >  16
                ;              ?B_CURRENTBANK * 16  if ?B_NBANKS <= 16
                ;              (see comments in macro SWITCH below for
                ;               explanation for why this is)
                ; 
                ; Currently, contains some code for supporting more than 63
                ; banks, though the functionality is not yet fully 
                ; implemented at this point in time.
SELECT          MACRO   N
                LOCAL   SWITCH_PREP, LOWER_64, UPPER_64
                PUBLIC  ?B_BANK&N

?B_BANK&N:
                MOV     A,?B_CURRENTBANK
                CJNE    A,#N,SWITCH_PREP
                CLR     A
                JMP     @A+DPTR

SWITCH_PREP:
  IF ?B_NBANKS <= 64
                ; Faster code for 64 banks or fewer.
    IF ?B_NBANKS <= 16
                SWAP    A  ;Lower byte of return address = ?B_CURRENTBANK * 4
    ELSE
                RL      A  ;Lower byte of return address = ?B_CURRENTBANK * 16
                RL      A
    ENDIF
                PUSH    ACC
                MOV     A,#HIGH ?BANK?SWITCH
                PUSH    ACC
                PUSH    DPL
                PUSH    DPH
                LJMP    ?B_SWITCH&N
  ELSE
                ; Slower code for ?B_NBANKS > 64 banks
                RL      A
                RL      A
                JB      ACC.0, UPPER_64

    LOWER_64:   PUSH    ACC
                MOV     A,#HIGH ?BANK?SWITCH
                PUSH    ACC
                PUSH    DPL
                PUSH    DPH
                LJMP    ?B_SWITCH&N

    UPPER_64:   ANL     A, 0FEh
                PUSH    ACC
                MOV     A,#HIGH ?BANK?SWITCH + 1
                PUSH    ACC
                PUSH    DPL
                PUSH    DPH
                LJMP    ?B_SWITCH&N
  ENDIF
                ENDM

;------------------------------------------------------------------------------
                ; ?BANK?SELECT is the code segment into which the repeated
                ; code of the SELECT macro is placed, as well as SWITCHBANK,
                ; the code for explicitly calling a bank switch in C.
?BANK?SELECT    SEGMENT  CODE
                RSEG    ?BANK?SELECT
CNT             SET     0
                REPT    ?B_NBANKS
                SELECT  %CNT
CNT             SET     CNT+1
                ENDM

                ; SWITCHBANK allows use of bank-switching for C programs
                ; prototype:  extern switchbank (unsigned char bank_number);
                ; This code is only accessed if explicitly called for in 
                ; the C program.
_SWITCHBANK:    MOV     A,R7
  IF ?B_NBANKS <= 16
                SWAP    A
  ELSE
                RL      A
                RL      A
  ENDIF
  IF ?B_NBANKS <= 64
                MOV     DPTR,#?BANK?SWITCH
                JMP     @A+DPTR
  ELSE
                JB      ACC.0, UPPER_64
                MOV     DPTR,#?BANK?SWITCH
                JMP     @A+DPTR
    UPPER_64:   ANL     A, 0FEh
                MOV     DPTR,#?BANK?SWITCH + 1
                JMP     @A+DPTR
  ENDIF

;------------------------------------------------------------------------------
                ; This macro is repeated once for every bank specified by 
                ; ?B_NBANKS.  The code contained in this macro does the
                ; actual bank switching.
                ;
                ; Because SELECT only uses the lower byte of the 16-bit 
                ; address (except when ?B_NBANKS > 64) to specify the
                ; location of the bank switch code, the total code size
                ; the SWITCH macro repeated for all the banks must stay
                ; below 256 bytes.  Therefore, the size of the code
                ; contained within SWITCH is critical to determining the
                ; maximum number of banks that can be supported.  For
                ; ?B_NBANKS <= 16, the code size is 16 bytes, allowing a
                ; maximum of 16 banks.  By moving much of the shared code
                ; in SWITCH outside of the macro, the code size is reduced
                ; to 4 bytes, allowing up to 64 banks, though taking a 
                ; penalty of two additional instructions (for the jump to
                ; the common code and for the add that must be done in
                ; the common code; see ?BANK?SWITCH below for the common
                ; code.)
                ;
                ; It is also because of SELECT that the code for SWITCH
                ; for each bank must begin on a multiple of 4 for 
                ; ?B_NBANKS > 16 or a multiple of 16 for ?B_NBANKS <= 16.
                ;
                ; By taking advantage of the lowest bit in the upper byte
                ; of the 16-bit address in SELECT, supporting 128 banks
                ; should be possible.
SWITCH          MACRO   N
                PUBLIC  ?B_SWITCH&N
  IF ?B_NBANKS > 16
                ORG     N * 4
  ELSE
                ORG     N * 16
  ENDIF

?B_SWITCH&N:
  IF ?B_NBANKS > 16
                MOV     A, #N
                AJMP    COMMON_SWITCH
  ELSE
                ; if ?BNBANKS <= 16
                MOV     DPTR,#?B_CMAP1_TAR_1
                MOV     A, #80h+N
    IF ?B_RTX = 1
                PUSH    IE
                CLR     EA
    ENDIF
                MOV     ?B_CURRENTBANK, #N
                MOVX    @DPTR, A
    IF ?B_RTX = 1
                POP     IE
    ENDIF
                RET
  ENDIF
                ENDM

;------------------------------------------------------------------------------
                ; ?BANK?SWITCH is the code segment into which the repeated
                ; code of the SWITCH macro is placed.  If ?B_NBANKS > 16,
                ; ?BANK?SWITCH also contains the common switch code.
                ;
                ; This is the place where support for 128 banks has not yet
                ; been implemented.  We need to insure that this entire 
                ; segment is located within a single page of memory, so that
                ; the AJMPs in SWITCH jump to the correct addresses.
?BANK?SWITCH    SEGMENT  CODE  PAGE
                RSEG    ?BANK?SWITCH
CNT             SET     0
                REPT    ?B_NBANKS
                SWITCH  %CNT
CNT             SET     CNT+1
                ENDM

                ; Common switch code if ?B_NBANKS is more than 16.
  IF ?B_NBANKS > 16
  COMMON_SWITCH:
                MOV     DPTR, #?B_CMAP1_TAR_1
    IF ?B_RTX = 1
                PUSH    IE
                CLR     EA
    ENDIF
                MOV     ?B_CURRENTBANK, A
                ADD     A, #80h
                MOVX    @DPTR, A
    IF ?B_RTX = 1
                POP     IE
    ENDIF
                RET
  ENDIF

;------------------------------------------------------------------------------
                END

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -