📄 l51_bank.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 + -