This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

MMU implementation.

Can a software memory management unit
be implemented on a 8032 microcontroller ?

Parents
  • The operation of the standard bank switching code is described in the comments in the standard L51_BANK.A51 file:

    ; THEORY OF OPERATION                                                         *
    ; -------------------                                                         *
    ; The section below describes the code generated by BL51 or LX51 and the      *
    ; operation of the L51_BANK.A51 module.  BL51/LX51 generates for each         *
    ; function that is located in a code memory bank and called from the common   *
    ; area or a different code bank and entry into the INTRABANK CALL TABLE.  The *
    ; INTRABANK CALL TABLE is located in the SEGMENT ?BANK?SELECT and listed in   *
    ; the Linker MAP file. The entries in that TABLE have the following format:   *
    ;                                                                             *
    ;   ?FCT?1:  MOV  DPTR,#FCT     ; Load Address of target FCT                  *
    ;            JMP  ?B_BANKn      ; Switch to Bank and Jump to Target Code      *
    ;                                                                             *
    ; Instead of directly calling the function FCT, the Linker changes the entry  *
    ; to ?FCT?1.  This entry selects the bank where the function FCT is located   *
    ; and calls that function via the routines defined in this L51_BANK.A51 file. *
    ; The L51_BANK.A51 file contains two sets of functions for each bank:         *
    ;                                                                             *
    ; ?B_BANKn    is a routine which saves the entry of the ?B_SWITCHn function   *
    ;             for the current active bank on the STACK and switches to the    *
    ;             bank 'n'.  Then it jumps to the address specified by the DPTR   *
    ;             register.  It is allowed to modify the following registers in   *
    ;             the ?B_BANKn routine:  A, B, R0, DPTR, PSW                      *
    ;                                                                             *
    ; ?B_SWITCHn  is a function which selects the bank 'n'.  This function is     *
    ;             used at the end of a user function to return to the calling     *
    ;             code bank.  Only the following registers may be altered in the  *
    ;             ?B_SWITCHn function:  R0, DPTR                                  *
    ;                                                                             *
    ; The current active bank is stored in ?B_CURRENTBANK.  RTX-51 uses this      *
    ; variable to restore the code bank after a task switch.  To get correct      *
    ; results, ?B_CURRENTBANK must be set to the code bank before the hardware    *
    ; switch is done, or the code banking sequences must be interrupt protected.  *
    The Triscend E5 had a single external address space, into which the 8032 core's CODE and XDATA spaces could be mapped. The E5 version of the standard banking file, L51_BANK_E5.A51 further describes the process:
    ; 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.

    I see no reason why this approach shouldn't be used to implement your paging - it's just that you actually have to re-load the code in the banked area, rather than just switching to a different "window" on the static banked code.

    This is effectively a software MMU:
    If the required function is already in the current Bank, it is just called (with a little overhead to check that it was in the same Bank);
    If the required function is not in the current Bank, this is effectively a page fault, and the required page must be loaded before calling the function.

    What more could you want?

Reply
  • The operation of the standard bank switching code is described in the comments in the standard L51_BANK.A51 file:

    ; THEORY OF OPERATION                                                         *
    ; -------------------                                                         *
    ; The section below describes the code generated by BL51 or LX51 and the      *
    ; operation of the L51_BANK.A51 module.  BL51/LX51 generates for each         *
    ; function that is located in a code memory bank and called from the common   *
    ; area or a different code bank and entry into the INTRABANK CALL TABLE.  The *
    ; INTRABANK CALL TABLE is located in the SEGMENT ?BANK?SELECT and listed in   *
    ; the Linker MAP file. The entries in that TABLE have the following format:   *
    ;                                                                             *
    ;   ?FCT?1:  MOV  DPTR,#FCT     ; Load Address of target FCT                  *
    ;            JMP  ?B_BANKn      ; Switch to Bank and Jump to Target Code      *
    ;                                                                             *
    ; Instead of directly calling the function FCT, the Linker changes the entry  *
    ; to ?FCT?1.  This entry selects the bank where the function FCT is located   *
    ; and calls that function via the routines defined in this L51_BANK.A51 file. *
    ; The L51_BANK.A51 file contains two sets of functions for each bank:         *
    ;                                                                             *
    ; ?B_BANKn    is a routine which saves the entry of the ?B_SWITCHn function   *
    ;             for the current active bank on the STACK and switches to the    *
    ;             bank 'n'.  Then it jumps to the address specified by the DPTR   *
    ;             register.  It is allowed to modify the following registers in   *
    ;             the ?B_BANKn routine:  A, B, R0, DPTR, PSW                      *
    ;                                                                             *
    ; ?B_SWITCHn  is a function which selects the bank 'n'.  This function is     *
    ;             used at the end of a user function to return to the calling     *
    ;             code bank.  Only the following registers may be altered in the  *
    ;             ?B_SWITCHn function:  R0, DPTR                                  *
    ;                                                                             *
    ; The current active bank is stored in ?B_CURRENTBANK.  RTX-51 uses this      *
    ; variable to restore the code bank after a task switch.  To get correct      *
    ; results, ?B_CURRENTBANK must be set to the code bank before the hardware    *
    ; switch is done, or the code banking sequences must be interrupt protected.  *
    The Triscend E5 had a single external address space, into which the 8032 core's CODE and XDATA spaces could be mapped. The E5 version of the standard banking file, L51_BANK_E5.A51 further describes the process:
    ; 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.

    I see no reason why this approach shouldn't be used to implement your paging - it's just that you actually have to re-load the code in the banked area, rather than just switching to a different "window" on the static banked code.

    This is effectively a software MMU:
    If the required function is already in the current Bank, it is just called (with a little overhead to check that it was in the same Bank);
    If the required function is not in the current Bank, this is effectively a page fault, and the required page must be loaded before calling the function.

    What more could you want?

Children