We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
Can a software memory management unit be implemented on a 8032 microcontroller ?
To page the memory, I'd use the same mechanism as for banked code. Rather than having the bank switch routines update a simple register as they would normally do, though, the custom "banking hardware" update routines that you write will do the paging instead. A call to a routine in a different bank thus jumps to the common bank, copies the new page into RAM, and then jumps to that routine that is now present in RAM. The page copy will be very slow, so you want to avoid calls to different banks where at all possible. Hopefully your program can be organized into highly independent phases of operation, so that you change these pages or overlays rarely. You could roll your own paging mechanism from scratch, but then you'll have to struggle with the linker to get it to understand that several blocks of code will be intentionally overlaid at the same address range. Telling the linker that the code is banked seems like an easy way to avoid that struggle. But you could also use the linker directives to manually assign addresses to all of your code segments. (I don't know without trying it whether you can force it to accept the conflicting address assignments and link the file anyway.) A hybrid scheme is to write the code as though it were banked, but have a null implementation for the actual bank switch routines. Paging would be done manually, with explicit calls inserted into the code. You'll save a little overhead on each function call this way (that which checks to see if the current bank is the one you need). But as soon as you accidentally call a function that's not really in the same bank as you have loaded, the code will go crazy. It'd be a lot safer to route all function calls through the bank switch routines to check, and perhaps add debug code to notify you when banks changed, so you can make sure it only happens when you expect.
Chetan Prabhu said: "Code banking concept will not work out for this design" Why not?? Drew Davis made the same suggestion: "To page the memory, I'd use the same mechanism as for banked code. Rather than having the bank switch routines update a simple register as they would normally do, though, the custom 'banking hardware' update routines that you write will do the paging instead." What is it about this approach that "will not work" in your system? If this can't work, what wil??
"1. re-map your 'banked' PM area from the 8032's CODE address space into its XDATA address space; 2. load code from the NAND flash into the XDATA-mapped 'banked' PM area; 3. map the 'banked' PM area back into the 8032's CODE address." If this will not work in your system then the answer to your question is simple: you cannot implement your MMU! You do realise, don't you, that the 8032 architecture has completely separate & distinct CODE and XDATA address spaces? The 8032 architecture has no instructions to write to its CODE space, and it cannot execute code from its XDATA space. Therefore, if you want to load stuff into SRAM, that SRAM must be mapped into the XDATA address space, and if you want to execute that stuff it must be mapped into the CODE address space. So, either you have to be able to switch it between the XDATA and CODE address spaces, or it must be permanently mapped into both address spaces
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 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.
"What more could you want?" What'd be really useful would be a hardware DMA unit to do the actual loading of the page...
You are going to need some code in ROM to boot this thing and load the first page. How will that be handled?